Skip to main content

Choose storage for a workload

Inspect 1.36

Most stateful workloads come down to a database, and if yours is one, the choice is already made: run it on local NVMe on bare metal, under a Kubernetes operator such as CloudNativePG. It is the fastest, most durable, and usually the cheapest option, and it is what the large majority of teams do. If that is you, go straight to and skip the comparison below. The next section is the short "why"; everything after it is for workloads that are not a database.

If you run a database, use local NVMe on bare metal#

An operator such as CloudNativePG for PostgreSQL runs the database as a cluster and handles the hard parts: replication across nodes, failover, backups, point-in-time restore, and version upgrades. On local disk there is no network hop and no storage translation layer in the path, and a bare metal server already includes its NVMe disks. At least three bare metal servers give you the same high availability, backups, and point-in-time recovery a managed database service sells, on hardware you own.

Reaching for a generic replicated volume instead looks simpler, but it is a trap: it puts a slower storage layer under the database, its replicas can drift out of sync, and it still leaves backup and recovery to you. Let the database do the replication; it is built for it.

Dev and staging can be simpler. A single database instance on a Hetzner Cloud volume keeps a test environment small, with no operator and no HA to run. A lone instance like that has no backups either, so keep nothing there you cannot afford to lose.

Not a database? Then compare, from two questions#

Two questions pick the storage: how many pods write at once, and what should happen to the data when Syself Autopilot replaces the node under it.

flowchart TD
    A[Not a database] --> B{How many pods write at once?}
    B -->|"Many, on different nodes"| C[Shared storage]
    B -->|"Just blobs, no filesystem"| D[Object storage]
    B -->|One writer| E{Data on node replacement?}
    E -->|Must follow the workload| F[Block storage]
    E -->|App keeps its own replicas| G[Local storage]

Question 1: how many writers#

  • One writer. Use block storage (standard) or local storage. Both are ReadWriteOnce: one node writes at a time.
  • Data shared across pods. Use over the S3 API. It is how most cloud-native apps share uploads, artifacts, and exports, and it keeps the data off your nodes.
  • Shared files an app cannot move to S3. Use a , JuiceFS or NFS. This is the fallback for an app that needs a real filesystem and cannot use the S3 API yet.

Most cloud-native apps keep state in a database or object storage, so they rarely need a shared filesystem. Reach for RWX only when an app genuinely needs many pods on one filesystem and cannot use object storage.

Question 2: what happens on node replacement#

Syself Autopilot rebuilds nodes during upgrades, scaling, and self-healing. Where your data lives decides whether it follows the workload:

  • The data must follow the workload anywhere it runs. Use a Hetzner Cloud volume, which Ceph-replicates the data three times and reattaches to the new node, or object and shared storage, which sit off the node entirely. Hetzner attaches at most 16 volumes to one server, so plan for that ceiling on a node that runs many of them.
  • The app keeps its own replicas. A workload that already runs replicas does not need the volume to move; give it for the lowest latency and let the app handle redundancy.
  • The data can be rebuilt from elsewhere. Scratch space and caches fit local disk too. If a server is lost, the workload starts fresh on another.

Scheduling drives this: a new cloud volume is created wherever the pod lands, while an existing volume instead pins the pod to where its data already lives. works through both directions.

For a single-writer application that is not a database and does not replicate, use a Hetzner Cloud volume and add a backup on top. covers exactly what a rebuild touches.

Cost and latency#

Latency is the sharpest divide between the backends. measures the gap between local disk and anything that crosses the network.

Backend Latency Follows the workload Cost driver
Local NVMe Lowest, no network hop No, tied to one server The server's disks
Hetzner Cloud volume Network round trip Yes, reattaches Per GB provisioned
Shared filesystem (JuiceFS) Object store plus metadata Yes, off-node Storage plus per-request cost
Object storage Object store round trip Yes, off-node Cheapest for large blobs

Which storage for which job#

Once a class fits the job, the lists its provisioner, access mode, and reclaim policy.

Job Backend Class
Production database via an operator Local NVMe on bare metal local-nvme
Single app instance, data must follow it Hetzner Cloud volume standard
Dev or staging database, kept simple Hetzner Cloud volume standard
Shared uploads or media across pods Shared filesystem juicefs
Backups, artifacts, large objects Object storage SeaweedFS or S3
CI scratch, rebuildable data Local disk local-nvme or local-ssd

Pair single-server storage with replication or backups#

Local storage carries no redundancy by itself: a lost disk means lost data unless something else holds a copy. Keep an off-server backup first, and add application-level replication on top. and show how.

Ready to set one up? Start with or .

Not sure which way to go, or want the operator-managed database on bare metal set up for you? The Syself Consulting team can design the storage architecture with you, or build and run it as a full service.