Flysystem: a core library with ten official adapters and a README made of links
Abstraction for local and remote filesystems
At a glance
- What is it?
- Flysystem wraps many PHP storage backends in one call shape, but the repository ships no install command, no example, and no capability matrix, and its newest tag is three years older than its last push. What the source does reveal is a small core repo, an adapter list split between official and community packages, and a test matrix that needs at least seven Docker services.
- Who is it for?
- Flysystem earns its place when one PHP application has to move the same storage calls between local disk and a hosted backend, and it is the wrong choice if you need Azure Blob, Dropbox or One Drive from an officially supported release, because those adapters live in other repositories with their own cadence.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- thephpleague/flysystem13,591 ★ · +4
| Repository | 2026-09-22 | 2026-11-14 |
|---|---|---|
| thephpleague/flysystem | 13.6k | 13.6k |
4 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The README is outbound links only, and two of them name master
The README on the 3.x branch is a list of outbound links and nothing else. There is no `composer require league/flysystem` line, no minimum PHP version, no note about directory permissions for the Local adapter, and not a single line of PHP. Installation details and the whole API live on flysystem.thephpleague.com, and among the links that point back into GitHub, the LICENSE link still names master while the CI badge links to the Actions page:
https://github.com/thephpleague/flysystem/blob/master/LICENSE
https://github.com/thephpleague/flysystem/actions?query=workflow%3A%22Quality+Assurance%22The default branch is 3.x, so `git clone` without arguments hands you code the README does not link to. For readers this means the repository cannot answer three questions before you write a line: which release to require, which PHP version supports it, and what a filesystem instance is constructed with. All three force you off the repository page.
S3 is on the official list twice, and two entries are not servers
The officially supported adapter list runs to ten: Local, FTP, SFTP, Memory, AWS S3, AsyncAws S3, Google Cloud Storage, MongoDB GridFS, WebDAV and ZipArchive. Read that list closely and the shape of the abstraction shows through. S3 appears twice, once through the AWS SDK and once through AsyncAws, so you choose a client library as well as a backend. Memory and ZipArchive are not servers at all: one is a process-local store, the other is an archive file, and both answer the same calls as a remote bucket would. GridFS is the reason the test compose file pulls mongo:7. What you do not get is a capability matrix. Nothing in the repository states which operations every adapter supports, how a failed rename surfaces, or whether one adapter raises an exception type another never throws. You are buying a shared call shape, not shared guarantees.
Azure, Dropbox and One Drive are community code with their own cadence
Twelve entries sit under third party adapters, and their placement matters if your platform is not on the official ten. Azure Blob Storage, Dropbox, Uploadcare and ReplicateAdapter live in other people's repositories, each with its own release schedule, PHP requirements and bug tracker. Two separate repositories target One Drive: `https://github.com/shitware-ltd/flysystem-msgraph` for Sharepoint 365 / One Drive using MS Graph, and `https://github.com/doerffler/flysystem-onedrive` for plain OneDrive. Choosing One Drive is a choice between two codebases, not a configuration switch. Google Drive is annotated as using regular paths, so it does not offer Drive's own folder semantics. The bunny.net entry links into a `tree/v3` branch, which shows community adapters pinning themselves to a major version of this library. The lock-in protection the project advertises is only as strong as the weakest adapter you depend on.
The adapter tests need seven servers, and one of them serves anonymous reads
Exercising the adapter tests means starting at least seven services. docker-compose.yml defines mongodb on 27017, a sabredav service that runs PHP's built-in server, two SFTP containers, two FTP daemons, and a WebDAV container:
sabredav:
image: php:8.1-alpine3.15
command: php -S 0.0.0.0:4040 /var/www/html/src/WebDAV/resources/server.php
webdav:
image: bytemark/webdav
ports:
- "4080:80"
environment:
AUTH_TYPE: Digest
USERNAME: alice
PASSWORD: secret1234
ANONYMOUS_METHODS: 'GET,OPTIONS'`ANONYMOUS_METHODS: 'GET,OPTIONS'` is the line worth reading twice. That container answers unauthenticated read requests, and every service shown in the file publishes a port to the host, so this compose file has no business running on a machine you do not control. The sabredav service mounts the working tree at /var/www/html and serves the library's own `src/WebDAV/resources/server.php`.
Both FTP daemons advertise localhost and reserve a passive port range
FTP appears twice in the compose file because two different server implementations are in the matrix. delfer/alpine-ftp-server runs with `USERS: 'foo|pass|/home/foo/upload'` and `ADDRESS: 'localhost'`, publishing 2121 and the passive range 21000-21010. stilliard/pure-ftpd runs with `PUBLICHOST: localhost`, `FTP_USER_NAME: foo`, `FTP_USER_PASS: pass`, `FTP_USER_HOME: /home/foo`, publishing 2122 and 30000-30009. Both are instructed to advertise localhost as the host clients should return to for passive data connections, which is right inside Docker and wrong for any client on another machine. Both also reserve a contiguous passive range that has to stay open through NAT and firewalls. If you point the FTP adapter at a real server, the two failures you meet first are a blocked passive port and a server handing back an address your client cannot route to.
SFTP is tested twice, and the second server offers only an ed25519 host key
SFTP is covered by two containers, and the second one is the informative case. The sftp service on port 2222 mounts users.conf, both host keys and one client public key:
- ./test_files/sftp/users.conf:/etc/sftp/users.conf
- ./test_files/sftp/ssh_host_ed25519_key:/etc/ssh/ssh_host_ed25519_key
- ./test_files/sftp/ssh_host_rsa_key:/etc/ssh/ssh_host_rsa_key
- ./test_files/sftp/id_rsa.pub:/home/bar/.ssh/keys/id_rsa.pubThe sftp_eddsa_only service on 2223 mounts users.conf and the ed25519 key but no RSA key, and it also mounts `sshd_custom_configs.sh` to `/etc/sftp.d/sshd_custom_configs.sh`. That is a server advertising a narrower set of host key algorithms, so host key negotiation belongs to the covered surface. The single `id_rsa.pub` file and the bar home directory show the other assumption baked in: one key type, one username, one fixed key path inside the container.
Security reports are routed to one inbox with no stated response window
Vulnerability reports go to a person, not to a public queue. The README's security guidance is one line: email [email protected] instead of using the issue tracker. The README states no response window, advisory identifier scheme or disclosure timeline. The tree does carry SECURITY.md, CODE_OF_CONDUCT.md and a top-level CHANGELOG.md alongside composer.json, phpstan.neon, phpstan-baseline.neon and .php-cs-fixer.dist.php, so the artifacts you would read for a fix do exist. What the guidance does not offer is any link between an emailed report and a tagged release. If your application accepts user uploads over S3, FTP or SFTP, that gap belongs in your risk calculation. It is a process fact rather than a code defect, and it is the kind of thing you find out after an incident instead of before one.
The newest tag is 3.16.0 from 2023 while the 3.x branch took a push in September
The release list and the branch history disagree by about three years. The newest tagged release shown is 3.16.0 from 2023-09-07, before it 3.0.0 from 2022-01-14 and 2.0.4 from 2021-04-05. The repository is not archived, and the default branch received a push on 2026-10-03, so commits have kept landing on 3.x long after the last tag. That changes what a version constraint means. Pinning 3.16.0 pins you to 2023 code, while installing from the default branch installs unreleased work that the tag history describes poorly. The documentation links show the same spread, with one page covering what is new in V2/V3 and another covering an upgrade from 1.x/2.x. No 4.x page is linked, so 3.x is the current line and the tag list understates it.
Editorial conclusion
Flysystem earns its place when one PHP application has to move the same storage calls between local disk and a hosted backend, and it is the wrong choice if you need Azure Blob, Dropbox or One Drive from an officially supported release, because those adapters live in other repositories with their own cadence. Before pinning a version, compare the 3.16.0 tag from 2023-09-07 against the 3.x branch, which took a push on 2026-10-03, and decide whether a single maintainer inbox is an acceptable path for security disclosure.
Frequently asked questions
What is a file storage system?
In Flysystem's terms it is a PHP library that offers one interface to interact with many types of filesystems, so the same calling code can target local disk, S3, FTP, SFTP or WebDAV and a storage vendor change does not force a rewrite of that code.
what is fly system
Flysystem is thephpleague/flysystem, an MIT licensed PHP library whose default branch is 3.x. It ships ten officially supported adapters, from Local and Memory through AWS S3, AsyncAws S3, Google Cloud Storage, MongoDB GridFS, WebDAV, FTP, SFTP and ZipArchive, and points at a list of community adapters for the rest.
Does the Flysystem README show how to install the package or run an example?
No. It carries no `composer require` line, no PHP version requirement and no code sample, so both installation and the filesystem API have to be read on flysystem.thephpleague.com or on the Packagist listing for league/flysystem.
Which Flysystem adapters are maintained outside the phpleague repository?
Twelve entries are third party, including Azure Blob Storage, Gitlab, Google Drive using regular paths, bunny.net / BunnyCDN, Sharepoint 365 / One Drive using MS Graph, OneDrive, Dropbox, ReplicateAdapter, Uploadcare, a useful adapters pack holding FallbackAdapter, LogAdapter, ReadWriteAdapter and RetryAdapter, a Metadata Cache adapter, and a lazy Migration adapter.
Do Flysystem's adapter tests require Docker to run?
The remote adapter tests do. docker-compose.yml defines mongodb, sabredav, webdav, sftp, sftp_eddsa_only, ftp and ftpd services on published host ports, so the Local and Memory paths can be exercised without them while the S3, SFTP, FTP, WebDAV and GridFS paths cannot.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/thephpleague-flysystem)Star history chart for your README
[](https://hysenlabs.com/projects/thephpleague-flysystem)Was this useful?