Skip to content

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 → bucket invoices, key q1.pdf
  • ZFS datasetzfs create tank/putfs/invoices for 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.