Skip to main content

Migrate from microsoft/azure-storage-blob

azure-oss/storage-blob is the package to move to if your current application still depends on microsoft/azure-storage-blob.

This is a very doable migration, but it is not a search-and-replace exercise. The big change is architectural: you move from one broad proxy object to a set of smaller clients that match how Blob Storage is actually shaped.

What changes, at a glance

AreaLegacy packageazure-oss/storage-blob
Main entry pointBlobRestProxyBlobServiceClient
How work is scopedPass container and blob names into methodsNarrow from service to container to blob clients
PHP targetPHP >=5.6PHP ^8.2
AuthConnection strings and SAS-style endpointsConnection strings, shared key, SAS, Microsoft Entra ID via azure-oss/identity
Documentation focusLegacy SDK usageModern Blob features, SAS, tags, versions, leases, Azurite

The mental-model shift to get right

Old code usually starts here:

use MicrosoftAzure\Storage\Blob\BlobRestProxy;

$blobClient = BlobRestProxy::createBlobService($connectionString);

New code starts one layer higher, then narrows with intent:

use AzureOss\Storage\Blob\BlobServiceClient;

$service = BlobServiceClient::fromConnectionString($connectionString);
$container = $service->getContainerClient('documents');
$blob = $container->getBlobClient('report.pdf');

That is the core idea of the migration. Once you stop thinking "one proxy, many method calls" and start thinking "service, then container, then blob", the rest falls into place much faster.

A low-risk migration plan

1. Replace the package

composer remove microsoft/azure-storage-blob
composer require azure-oss/storage-blob

2. Keep auth boring on the first pass

If the current app works with a connection string, keep using a connection string first:

$service = BlobServiceClient::fromConnectionString($connectionString);

That keeps the first deployment focused on the client API shift instead of mixing in an auth redesign.

3. Replace repeated names with scoped clients

Old style:

$blobClient->createBlockBlob($containerName, $blobName, $contents);

New style:

$service = BlobServiceClient::fromConnectionString($connectionString);
$container = $service->getContainerClient($containerName);
$blob = $container->getBlobClient($blobName);

$blob->upload($contents);

If you see the same container name threaded through a file again and again, that is your sign to introduce a BlobContainerClient.

4. Re-test every signed access path

Blob migrations often look successful until the first generated URL hits production.

Verify:

  • blob SAS URLs
  • container SAS URLs
  • account-level SAS workflows, if you use them
  • response header overrides on signed links
  • any snapshot- or version-specific URL behavior

5. Only modernize auth after the SDK move is stable

Once the package migration is settled, decide whether you want to move beyond connection strings toward:

  • shared key credentials
  • Microsoft Entra ID
  • workload identity
  • managed identity

Those are good upgrades. They are just easier to reason about after the client migration is already done.

What tends to get better immediately

  • code that reflects the actual shape of Blob Storage
  • cleaner boundaries between service, container, and blob operations
  • better docs for tags, versions, leases, listing, and SAS generation
  • a path into the Flysystem and Laravel packages that use the same Blob foundation
  • clearer local development guidance through Azurite

Migration checklist

  • Replace BlobRestProxy imports and construction
  • Introduce BlobServiceClient, then scope down to container and blob clients
  • Re-test uploads, downloads, deletes, metadata, and listing
  • Re-test all SAS and signed URL flows
  • Defer auth modernization until after the client migration is green

Keep reading