league/flysystem
Flysystem is a filesystem abstraction for PHP that lets you work with local disks, S3, FTP, and more through one consistent API. Swap storage backends without changing your code, with adapters, streams, and strong integration across frameworks like Laravel.
league/flysystem is a perfect fit for Laravel applications requiring multi-cloud storage support (S3, GCS, Azure, SFTP, etc.) or local filesystem operations in a unified way. It aligns with Laravel’s dependency injection and service container patterns, allowing seamless integration with existing storage systems (e.g., replacing Storage::disk() with a custom Filesystem instance).Storage::disk()) via the league/flysystem-laravel bridge, but can also be used standalone for non-Laravel PHP projects.Storage facade by:
Filesystem instance in AppServiceProvider.flysystem package for deeper Laravel integration.Storage for selective adoption.Storage with league/flysystem for full abstraction.| Risk Area | Assessment | Mitigation Strategy |
|---|---|---|
| Adapter Complexity | Some adapters (e.g., SFTP, WebDAV) require additional dependencies (e.g., phpseclib, sabre/dav). |
Use composer autoload and config validation to enforce required packages. |
| Performance Overhead | Async AWS S3 and Google Cloud Storage may introduce latency for large operations. | Benchmark batch operations (e.g., listing 10K+ files) and optimize chunking. |
| Error Handling | Some adapters (e.g., FTP, SFTP) have inconsistent error messages. | Implement a custom error decorator to normalize exceptions. |
| PHP 8.4+ Compatibility | Minor deprecations fixed in 3.25.1, but future PHP versions may require updates. | Monitor PHP compatibility and backport fixes if needed. |
| State Management | Connection leaks (e.g., SFTP, FTP) can occur if not properly closed. | Use dependency injection with explicit disconnect methods (e.g., disconnect()). |
spatie/flysystem-circuit-breaker) be used?Log facade)?| Component | Integration Strategy | Laravel Synergy |
|---|---|---|
| Core Laravel Storage | Replace Storage::disk() with Filesystem instances where needed. |
Use spatie/laravel-flysystem for seamless DI. |
| AWS S3 | Replace aws-sdk-php/v3 with league/flysystem-aws-s3-v3 for v3 compatibility. |
Leverage Laravel’s config/filesystems.php for adapter configuration. |
| Google Cloud Storage | Use league/flysystem-google-cloud-storage with service account credentials. |
Store credentials in Laravel’s env files or Vault. |
| SFTP/FTP | Use league/flysystem-sftp with phpseclib/phpseclib. |
Configure via Laravel’s config or env variables. |
| Local Filesystem | Extend Laravel’s local disk with custom logic (e.g., visibility retention). |
Use Filesystem::createLocal() with path prefixing. |
| MountManager | Combine multiple storage backends (e.g., S3 + Local cache). | Register as a Laravel service provider for dynamic mounting. |
Phase 1: Pilot Adoption (Low Risk)
Storage facade alongside league/flysystem for comparison.// Before (Laravel)
Storage::disk('s3')->put('file.txt', 'content');
// After (Flysystem)
$filesystem = new Filesystem(new AwsS3V3Adapter(...));
$filesystem->put('file.txt', 'content');
Phase 2: Full Integration (Medium Risk)
Storage usages with Filesystem instances.$this->app->bind('flysystem.s3', function () {
return new Filesystem(new AwsS3V3Adapter(...));
});
league/flysystem adapters.Phase 3: Advanced Features (High Value)
$filesystem->temporaryUrl('file.txt', now()->addHour());
| Feature | Laravel Storage | league/flysystem | Notes |
|---|---|---|---|
| Disk Configuration | ✅ Yes | ✅ Yes | Use config/filesystems.php or custom config. |
| Filesystem Events | ✅ Yes | ❌ No | Implement custom event listeners if needed. |
| Symbolic Links | ✅ Yes | ✅ (Local only) | Not supported on all adapters (e.g., S3). |
| Visibility/ACLs | ✅ Partial | ✅ Full | Flysystem supports S3 ACLs, GCS visibility, etc. |
| Streaming Uploads | ✅ Yes | ✅ Yes | Use putStream() for large files. |
| Async Operations | ❌ No | ✅ (Async AWS) | Requires league/flysystem-async-aws-s3. |
| Path Prefixing | ✅ Yes | ✅ Yes | Use PathPrefixingAdapter for nested paths. |
How can I help you explore Laravel packages today?