Skip to main content
If you’re moving an existing application to Laravel Cloud, you likely already have files sitting in another provider’s bucket. Copying everything before you cut over can be slow and can force downtime. Laravel’s read-through filesystem driver lets you cut over immediately instead. When a file is missing from your new Laravel Cloud Object Storage bucket, Laravel reads it from your old provider and copies it into the new bucket for next time. Your files move over as your application accesses them.

Before you start

The read-through driver requires Laravel 13.26.0 or later. Run composer update laravel/framework before continuing. If your old provider is S3-compatible, you’ll also need league/flysystem-aws-s3-v3. See the Object Storage prerequisites.
The read-through driver works with any two Flysystem-compatible disks, including ones that aren’t S3-compatible. You can also use it to move off local disk storage or another provider’s driver.

Step 1: Create your Laravel Object Storage bucket

If you haven’t already, create a Laravel Object Storage bucket and attach it to your environment. Note its disk name (for example, r2). Laravel Cloud automatically injects the AWS_* credentials your application needs to reach it. Leave your old provider’s credentials in place. You’ll need them for the fallback disk in the next step.

Step 2: Configure your old provider as a fallback disk

In config/filesystems.php, add a disk entry for your old provider using whatever credentials it requires:
Laravel Cloud injects credentials only for the bucket attached to your environment, so add your old provider’s credentials as custom environment variables under your environment’s settings.

Step 3: Add a read-through disk

Combine your new Laravel Cloud bucket (primary) and your old provider (fallback) into a single read-through disk:
Reads check the new bucket first. If the file isn’t there yet, Laravel reads it from the old provider, copies it into the new bucket, and returns it within the same request. Writes and directory listings always go to the new bucket, so anything your application saves after cutover lands directly on Laravel Cloud. Existence and metadata checks, such as Storage::exists and Storage::size, consult either disk without triggering a copy.
By default, a failed promotion doesn’t fail the read. For example, if the new bucket is briefly unreachable, Laravel returns the file from the fallback disk. If you’d rather the read throw an exception, set 'throw_on_promotion_failure' => true on the disk. Either way, watch your logs during the migration window. Laravel Nightwatch reports exceptions like these in real time, so you can catch credential or permission issues with either disk early.

Step 4: Point your application at the read-through disk

Update FILESYSTEM_DISK to your new read-through disk, and redeploy:
From this point on, every file read through Storage::disk('assets') or the default Storage facade comes from whichever bucket has the file. If the file is still on your old provider, Laravel copies it to Laravel Cloud as part of the read.

Step 5: Speed up the migration (optional)

Waiting for real traffic to touch every file can leave rarely accessed files on your old provider indefinitely. To migrate everything up front instead, loop over the fallback disk’s contents and read each file through the read-through disk:
For large buckets, dispatch a queued job per file or per batch of files instead of running the loop inline.

Step 6: Retire the old provider

Once every object in your old bucket exists in Laravel Cloud, remove the fallback. To confirm the migration is complete, use your storage provider’s inventory or compare the object keys in both buckets. Then follow these steps:
  1. Set FILESYSTEM_DISK back to your bucket’s disk name (r2).
  2. Remove the legacy and assets disk entries from config/filesystems.php.
  3. Redeploy.
  4. Cancel or delete the bucket with your old provider.