Turn any Linux box with a btrfs disk into a very capable storage backend. Instant snapshots, writable clones, per-volume quotas, compression, NoCOW (no copy-on-write) for databases, and automatic NFS exports. All from a single Go binary and a REST API.
Successor: Active development moves to a hard fork named ButterStore, which reframes the project around what it has actually become: a general-purpose btrfs storage backend where the Kubernetes CSI driver is one of several integrations. Migration is a drop-in: tokens, REST API, CLI, Helm values, StorageClasses, PVCs, and VolumeSnapshots all keep working. A migration guide ships with the first ButterStore release. Once ButterStore ships, this repo gets archived. Published artifacts (container images, Helm charts) stay available.
The name plays on the colloquial pronunciation of btrfs as "butter-FS" plus its role as a storage backend.
Most storage solutions are built for the data center. Ceph, Longhorn, and OpenEBS bring clustering overhead that doesn't make sense when you have one server (or two for HA) and a btrfs filesystem.
btrfs-nfs-csi is not a distributed storage system. If you need data replication across many nodes, look at Longhorn or Ceph. If you have one server with good disks and want storage that stays out of your way, this is it.
Know your filesystem. btrfs is powerful but has trade-offs. RAID 5/6 is not production-ready. Quotas (qgroups) add overhead on write-heavy workloads, use simple quotas (btrfs quota enable -s, kernel 6.7+) to reduce it. CoW causes fragmentation over time (use NoCOW for databases). Regular scrubs are recommended to catch silent corruption early. None of these are deal-breakers, but you should be aware of them.
| btrfs-nfs-csi | Longhorn | democratic-csi | csi-driver-nfs | local-dir | |
|---|---|---|---|---|---|
| Min. nodes | 1 (2+ with DRBD) | 1 (3 for HA) | 1 | 1 (2+ with DRBD) | 1 |
| ReadWriteOnce | Yes | Yes | Yes | Yes | Yes |
| ReadWriteMany | NFSv4 (native) | NFSv4 (share-manager) | NFS (some backends) | Native (NFS) | -- |
| Snapshots | Instant | Incremental CoW | Instant | Copy-based | -- |
| Clones | Zero-copy | V2: linked | Clone | Copy-based | -- |
| Compression | Per-volume | LZ4/Gzip (backup-only) | Per-StorageClass | Gzip (snapshots) | -- |
| Checksums | Built-in | CRC64 (snapshots, off) | Built-in | -- | -- |
| NoCOW | Per-volume | Not required | Tuning (recordsize) | Not required | Depends on FS |
| Online expand | Yes | Yes | Yes | -- | -- |
| Size limits | Qgroups | Block device | Refquota | -- | -- |
| Multi-tenant | Built-in | -- | -- | -- | -- |
| Overhead | <128 MB + ~256 MB/TB (btrfs) | 500 MB+ per node | 1 GB+ per TB (ARC) | ~30 MB | ~30 MB |
| Deployment | External server* | Kubernetes nodes | External server | External server | Kubernetes nodes |
| Setup | Single binary + Helm | Helm (multi-component) | Helm | Helm | Helm / kubectl |
| Integrations | REST API, CLI, K8s, ... | REST API, CLI, K8s | Kubernetes | Kubernetes | Kubernetes |
| Best for | Homelab, single-server | Multi-node clusters | ZFS/TrueNAS shops | Existing NFS server | Local disk |
* If you don't care about redundancy and security, you can install the agent directly on your single master node and your workers can use it. This also gives you a migration path if you later want to move the agent to a dedicated Linux box.
This comparison represents my personal point of view. No offense intended to any of these great projects. Improvements are welcome.
+5Gi).zstd, lzo, zlib with levels, configurable per volume.chattr +C for databases (PostgreSQL, MySQL, etcd).readonly, mounter, user, admin) and optional per-token identity. created-by ownership scopes mutations to the creator within a tenant. See rbac.md.agents login once.-w). Auto-refreshing output for any list/get command.-c name,size,used). Show only what you need.-l env=prod). Filter resources by label.expand my-vol +5Gi.AGENT_CSI_IDENTITY to view or manage resources created by other integrations. Names stay unique across identities.
One command on any Linux host with a btrfs filesystem (Debian, RHEL, Arch, SUSE):
curl -fsSL https://raw.githubusercontent.com/erikmagkekse/btrfs-nfs-csi/main/scripts/quickstart-agent.sh \
| sudo -E bash
The script installs Podman, NFS, btrfs-progs, enables quotas, and starts the agent as a Quadlet container. Save the tenant token printed at the end. For advanced setups see the Installation docs.
To auto-format a block device as btrfs:
AGENT_BLOCK_DISK=/dev/sdb curl -fsSL \
https://raw.githubusercontent.com/erikmagkekse/btrfs-nfs-csi/main/scripts/quickstart-agent.sh \
| sudo -E bash
Environment variables
| Variable | Default | Description |
|---|---|---|
AGENT_BASE_PATH |
/export/data |
btrfs mount point |
AGENT_TENANTS |
default:<random> |
tenant:token pairs |
AGENT_LISTEN_ADDR |
:8080 |
Listen address |
AGENT_BLOCK_DISK |
Optional block device to auto-format as btrfs | |
VERSION |
0.11.2 |
Image tag |
Log into the agent once, the CLI saves the endpoint to ~/.btrfs-nfs-csi/config.json (file 0600) and uses it as the default for every subsequent command:
btrfs-nfs-csi agents login prod --url http://10.0.0.5:8080
# enter token at the no-echo prompt, or pipe it in (Docker-style):
# echo "$AGENT_TOKEN" | btrfs-nfs-csi agents login prod --url http://10.0.0.5:8080
btrfs-nfs-csi volume create my-app 10Gi
btrfs-nfs-csi volume list
btrfs-nfs-csi snapshot create my-app before-deploy
btrfs-nfs-csi stats
For one-off shells or CI, AGENT_URL and AGENT_TOKEN env vars (or --agent-url/--agent-token flags) still work and take precedence over the saved agent. See Operations: Saved Agents for agents ls/use/verify.
That's it. The agent manages btrfs subvolumes, NFS exports, and quotas. The CLI talks to the agent via REST API. Everything else (container orchestrator integrations, automation, custom tooling) builds on top.
Create, expand, compress, and label volumes with per-volume quotas and NoCOW for databases.

Instant btrfs snapshots. Writable clones from snapshots or volumes, zero-copy and zero-wait.

Add and remove NFS exports per volume, per client, directly from the CLI.

Per-device I/O stats, error tracking, and filesystem scrubs, all from the CLI.

The agent exposes a REST API. Any system that can make HTTP calls can manage volumes, snapshots, and exports. The CLI and all integrations use the same API.
| Integration | Status | Description |
|---|---|---|
| Kubernetes (CSI Driver) | Beta | This is where it all started. PVCs, VolumeSnapshots, ReadWriteMany via NFS. |
| Nomad | Idea | CSI plugin for HashiCorp Nomad. |
| Docker | Idea | docker volume create support. |
| Proxmox | Idea | Storage plugin for Proxmox VE. |
The Go client makes it easy to build your own integrations:
import (
"github.com/erikmagkekse/btrfs-nfs-csi/agent/api/v1/client"
"github.com/erikmagkekse/btrfs-nfs-csi/agent/api/v1/models"
)
c, _ := client.NewClient("http://10.0.0.5:8080", "your-token", "my-app")
vol, _ := c.CreateVolume(ctx, models.VolumeCreateRequest{
Name: "my-volume",
SizeBytes: 10 * 1024 * 1024 * 1024,
Compression: "zstd",
Labels: map[string]string{"env": "prod"},
})
c.CreateVolumeExport(ctx, vol.Name, models.ExportCreateRequest{
Client: "10.0.1.1",
})
Enable AGENT_API_SWAGGER_ENABLED=true and the agent serves the full spec at /swagger.json. Want to build an integration? We'd love a PR.
Have an idea or want to build an integration? Open an issue or submit a PR.
| Document | Description |
|---|---|
| Installation | Agent setup, container build |
| Configuration | Environment variables, parameters, TLS |
| RBAC | Tokens, roles, identity, ownership |
| Architecture | Volume lifecycle, ID formats, directory structure, HA |
| Operations | Snapshots, clones, expansion, compression, NoCOW, quotas, NFS exports |
| Metrics | Prometheus metrics, PromQL examples |
| Integrations | Kubernetes CSI driver (more coming) |
| Release | Release process, versioning, CI pipeline |
Work in progress.
The handbook will cover real-world recipes, best practices, and operational guides. Stay tuned.
go build -ldflags "-X main.version=$(cat VERSION) -X main.commit=$(git rev-parse --short HEAD)" \
-o btrfs-nfs-csi ./cmd/btrfs-nfs-csi
Contributions are herzlich willkommen! Whether it's a bug fix, a new integration, or improved docs, feel free to open an issue or submit a PR.
See docs/release.md for the release process and CI pipeline.
$ claude mcp add btrfs-nfs-csi \
-- python -m otcore.mcp_server <graph>