Data model
PutFS stores files on a plain directory hierarchy. It doesn't enforce any structure – PUT /hello.txt works fine.
For multi-tenant or multi-application deployments, there's a logical model:
tenant → a PutFS deployment (maps to a ZFS pool or data root)
└── dataset → first path segment (maps to S3 bucket, ZFS dataset)
└── object → everything after (just a file)
https://acme.putfs.example.org/invoices/q1-2024.pdf
^^^^ ^^^^^^^^ ^^^^^^^^^^^^
tenant dataset object path
On disk:
/srv/putfs/
├── invoices/ ← dataset
│ └── q1-2024.pdf ← object
└── contracts/ ← dataset
└── nda.pdf ← object
No metadata database. No index. No proprietary format. If PutFS disappeared tomorrow, your files would still be there, readable with ls.
Tenants
A tenant is a single PutFS deployment – one server, one nginx, one data root. Isolation between tenants is at the deployment level (separate servers, separate DNS, separate auth). Or, when running multiple instances on one server, tenant isolation can be enforced via different mount points or zfs pools for the data root.
Could map to: an application, a team, an AWS region equivalent, a customer.
Datasets
The first path segment. This is a convention, not enforced by PutFS – it exists because the S3 API uses path-style addressing where the first segment is the bucket (PUT /<bucket>/<key>). When running the S3 endpoint, the first path segment is treated as the bucket name.
Maps naturally to:
- S3 bucket (path-style) –
PUT /invoices/q1.pdf→ bucketinvoices, keyq1.pdf - ZFS dataset –
zfs create tank/putfs/invoicesfor per-dataset quotas, snapshots, encryption - A directory – on any filesystem, it's just a folder
Datasets are created implicitly on first PUT. No CreateBucket API needed.
Objects
Everything after the dataset prefix. Can be nested: /invoices/2024/q1/report.pdf is fine. Directories are created automatically.
No structure required
PutFS doesn't validate or enforce this model. All of these work:
curl -X PUT -d "hi" http://localhost:8000/hello.txt
curl -X PUT -d "hi" http://localhost:8000/a/b/c/d/e/f.txt
curl -X PUT -d "hi" http://localhost:8000/invoices/q1.pdf
It's just files in directories. The tenant/dataset model is a convention for ops and the s3 path-style implementation.