Laravel 13 introduces a read-through filesystem driver that composes a primary and fallback disk to enable zero-downtime migrations between object storage providers, such as S3 to R2. New writes go to primary, reads fall back to the legacy store and can be promoted (copied) into primary on access. The post covers the read path logic, filesystem operation routing, promotion failure modes (best-effort vs strict), streamed reads for large files, metadata caveats, delete semantics, egress cost implications, a full migration playbook, and alternative tools like Cloudflare Sippy, Super Slurper, rclone, and AWS DataSync.
Table of contents
# One logical disk across two stores# The read path# The filesystem contract# Promotion failures# Streamed reads and temporary storage# Object metadata# URL resolution# Deletes and mutable keys# Egress costs during migration# Completing the migration# AlternativesQuestions this post answers
How does Laravel 13's read-through filesystem driver handle migrating objects from S3 to R2 without downtime?
It composes a primary disk (destination, e.g. R2) and a fallback disk (source, e.g. legacy S3) behind Laravel's filesystem API. New writes go directly to primary. Reads check primary first, fall back to the source on a miss, and copy (promote) the object into primary during that same request, so subsequent reads use primary. Track Laravel framework releases like this on daily.dev when planning a storage migration.
What is the difference between best-effort and strict promotion in Laravel's read-through filesystem driver?
Best-effort mode, the default, absorbs promotion write failures silently and still returns the fallback content, leaving the object on fallback for a later retry. Setting throw_on_promotion_failure to true (along with the disk's throw option) turns a failed copy into an UnableToReadFile error instead of silently succeeding with fallback data. Developers debugging storage migration edge cases can follow Laravel updates on daily.dev.
What are the R2 and S3 costs involved when migrating objects from AWS S3 to Cloudflare R2?
As of August 2026, R2 charges $0.015 per GB-month storage, $4.50 per million Class A operations (first 1 million free monthly) and $0.36 per million Class B operations (first 10 million free), with free internet egress. AWS charges around $0.09 per GB for data transfer out after the first 100 GB free monthly, plus $0.0004 per 1,000 S3 GET requests in US East. Engineers estimating migration egress costs can follow cloud pricing changes on daily.dev.