Persistent Volumes
Attach a writable disk to your service that survives redeploys and container restarts. Use it for uploads, caches, SQLite databases — anything that needs to outlive a single container.
/tmp — already mounted as tmpfs in every container. The platform exports HOSTSTACK_TMP_DIR=/tmp so portable apps can write to $HOSTSTACK_TMP_DIR/.... Use volumes for data that must persist.Declare in hoststack.yaml (recommended)
Infrastructure-as-Code: every deploy reconciles the declared disk into the service. The dashboard reflects what your yaml says.
services:
api:
type: web_service
start:
command: bun apps/api/src/index.ts
disk:
name: data
mountPath: /var/data
sizeGB: 10- name — short identifier (lowercase, hyphens). Treated like a docker volume name; changing it after data is written will detach the old disk.
- mountPath — absolute in-container path the disk mounts at.
- sizeGB — 10–10240 (10 GB–10 TB), default 10. Disk capacity in gibibytes; Hetzner block volumes have a hard 10 GB minimum. Billed at €0.10/GB·month for extra storage beyond the service-included disk.
Dashboard
Open the service → Volumes tab. You can attach, resize (grow only), and delete volumes there. Disks declared in hoststack.yaml show up automatically after the next deploy.
CLI
# List volumes attached to a service
hoststack volumes list <service-id>
# Attach a new volume
hoststack volumes create <service-id> data /var/data --size 10
# Grow a volume (cannot shrink)
hoststack volumes resize <service-id> <volume-id> 20
# Detach and deprovision
hoststack volumes delete <service-id> <volume-id>SDK
import { HostStack } from '@hoststack.dev/sdk';
const client = new HostStack({ apiKey: process.env.HOSTSTACK_API_KEY! });
await client.volumes.create('team_…', 'svc_…', {
name: 'data',
mountPath: '/var/data',
sizeGb: 10,
});
const { volumes } = await client.volumes.list('team_…', 'svc_…');
for (const v of volumes) {
console.log(v.name, v.mountPath, v.sizeGb, v.status);
}MCP
Available tools: list_volumes, create_volume, update_volume, delete_volume. They all work with service publicIds (svc_…) and volume publicIds (vol_…) — no need to look up numeric IDs first.
Lifecycle & reliability
- Attach creates a docker volume on the host on first deploy. Data persists across redeploys, restarts, and service suspends.
- Resize only supports growing. Filesystems can't safely shrink under live data.
- Delete marks the row
deletingand dispatches deprovision to the host agent. If the agent is offline, a 5-minute reaper retries until it acks. The disk is destroyed once the agent confirms — back up data first. - Multiple agents — a service is pinned to one host, so its volume lives on that host. Migrating between hosts is a manual restore from snapshot.
Billing
Storage is metered per GB-month. The control plane sums the sizeGb of every active volume across your team once a day and reports it to Stripe under volume_storage_gb. Your invoice line-items show the GB-month total. Volumes marked deleting stop billing immediately, even before the host agent finishes the deprovision.