platformcommunity/flysystem-bunnycdn
A Flysystem adapter for BunnyCDN storage that lets Laravel apps use BunnyCDN as a filesystem disk. Upload, read, delete, and list files through Laravel's Storage facade, with support for Flysystem v3 and BunnyCDN storage zones. Simple to configure and framework-friendly.
Architecture fit. This package is a thin, single-purpose adapter: it implements the Flysystem 3 FilesystemAdapter contract on top of BunnyCDN's Storage API. That is the right shape for a Laravel codebase — it slots in behind Storage::disk('bunny') and requires no changes to application-level file handling if the team already codes to the Flysystem interface. Feature coverage is credible for the mainstream cases: writeBatch (v3.3.5), true streamed reads/writes (v3.3.6), deep listContents, path prefixing, SHA-256 checksum reuse, and PublicUrlGenerator support (v3.3.0). Temporary URL support landed in v3.3.8 and was refined twice within two releases (pull-zone prefixing, then query-parameter passthrough in v3.3.10), which is a good sign of active maintenance but also a sign the private-content path is young.
Integration feasibility. Low friction. Composer install, a disk entry in config/filesystems.php, four environment values (storage zone, API key, region, pull zone), and the existing Storage facade keeps working. No service provider, no migrations, no schema. The realistic effort is configuration and credential handling, not code. The main non-obvious work is Bunny-specific semantics: public vs. private pull zones, token authentication for signed URLs, and the fact that temporary URLs depend on a pull zone being configured rather than being a pure storage-zone capability.
Technical risk. This is the weakest dimension. Adoption signals are thin — 95 stars and zero dependents — meaning very little production mileage is visible in the ecosystem and a correspondingly small pool of people who have hit edge cases before you. Historical changelogs show a pattern of correctness bugs in exactly the operations that are most expensive to get wrong: a delete operation that could remove all contents (fixed v3.3.3), delete-directory raising on NotFound, move-to-same-destination deleting the source (v3.3.4), inconsistent datetime formats, uppercase-region base-URL breakage, and prefix-path regressions across multiple releases. These are all fixed, and the fixes were released promptly, but the class of bug matters more than the count: destructive filesystem semantics are high-blast-radius. Secondary risks: a documented spec deviation where text/plain mime types raise UnableToRetrieveMetadata; a test suite that partly depends on a live environment; and a release history with hotfix churn (3.3.7 → 3.3.8 → 3.3.9). Mitigants are real, though: MIT license, narrow surface area (~15 adapter methods), and a small upstream client, which together make an internal fork or vendor-pin a genuinely viable contingency rather than a rewrite.
Key questions.
Stack fit. Targets Laravel with Flysystem 3.x and PHP 8.0+ (v3.0.0 raised the floor; the v2 line still covers PHP 7.4). That aligns with current Laravel releases. The adapter also works outside Laravel for any Flysystem consumer, so the same driver can serve queue workers, CLI tooling, and non-HTTP services.
Migration path. Because everything goes through the Storage facade, moving from S3, DigitalOcean Spaces, or local disk is largely a config change plus a data backfill. The migration is not, however, free of semantics: S3-style ACLs and presigned PUT URLs have no direct equivalent, so any client-side direct-upload flow built on temporaryUploadUrl or S3 POST policies needs redesign — typically a signed app endpoint that streams to Bunny, or a Bunny-specific upload path. Visibility handling also differs, so code that branches on public/private per object should be audited before cutover.
Compatibility. Pin the adapter minor version and keep Dependabot/Renovate active; several recent minors changed behavior rather than only adding APIs. Note the historical breaking renames (BunnyCDNStorage → BunnyCDNClient in the v1.2/v2.2 era) as evidence that class-level names are not a stable contract across majors. Verify the Flysystem major in composer.json before assuming v3 semantics — a v2-era lockfile will resolve an incompatible adapter line.
Sequencing.
MediaStore service so no domain code calls the adapter directly — this is what makes the fork contingency cheap.Maintenance. Community-maintained, no vendor SLA, small contributor base. Budget a recurring line item: version pinning, changelog review on each release, and a named owner. The honest risk is abandonment; the honest mitigation is that the surface is small enough to fork and the license permits it. Treat "we can maintain this ourselves" as a real, costed option rather than a hypothetical.
Support. GitHub issues are the only channel — no commercial escalation path via the package itself. Escalation therefore goes to BunnyCDN support for platform-side incidents and to our own fork for adapter-side defects. Set expectations accordingly: adapter bugs are internal tickets, not vendor tickets.
Scaling. Delivery scaling is Bunny's problem and that is the point of the choice — edge caching and CDN offload are the value. Ingest and API-side scaling are ours: watch Storage API rate limits and per-request latency, prefer writeBatch over per-file loops, and be careful with deep listContents on large prefixes, which can be slow and memory-heavy compared with a purpose-built directory listing. Cache directory listings rather than recomputing them per request.
Failure modes to instrument.
deleteDirectory on a mistyped prefix, move-to-same-destination. Guard with prefix assertions and never expose raw user input as a path root.UnableToRetrieveMetadata (notably text/plain) will surface as exceptions in code that assumes metadata always resolves. Wrap these reads.logo.png does not necessarily update what users see. This needs an explicit purge step in the deploy or upload path, and it is the most likely "worked in staging, wrong in production" surprise.Ramp-up. Low for anyone fluent in Laravel filesystems — a half day to first successful upload, roughly a week to comfortable production use including token-auth private content and cache purging. The learning curve is Bunny platform concepts (storage zones vs. pull zones, token auth, region selection, purge API), not the PHP package. Plan for one engineer to own both the adapter integration and the Bunny account configuration, because the failure modes straddle the boundary between them.
How can I help you explore Laravel packages today?