On this page

A Volume is a persistent block device attached to a compatible computer. It survives ordinary computer restarts while the host-local volume remains healthy. It does not automatically move across hosts. Useful cases include:

  • SQLite databases that need to be local to the runtime.
  • Caches you can’t afford to lose on restart.
  • LLM model weights downloaded once and shared across instances.
  • Workloads that legitimately need filesystem state (not just key-value).

Volumes are NOT useful for:

  • Stateful databases - use Postgres instead. It scales better, backs up automatically, and survives host failures.
  • User-uploaded files - use Storage / Buckets. Cheaper, browser-uploadable, geo-replicable.
  • Shared state across multiple replicas - volumes are typically attached to ONE runtime instance.

Create

Use it your way — API, CLI, or SDK

No SDK required.

Raw API (curl): the raw API takes size_bytes and a backend (use local).

# Create a 50 GB volume
curl -X POST https://api.miosa.ai/api/v1/volumes 
  -H "Authorization: Bearer $MIOSA_API_KEY" -H "Content-Type: application/json" 
  -d '{"name": "model-weights", "size_bytes": 53687091200, "backend": "local"}'

# Attach it to a running computer at a mount path
curl -X POST https://api.miosa.ai/api/v1/computers/COMPUTER_ID/volumes 
  -H "Authorization: Bearer $MIOSA_API_KEY" -H "Content-Type: application/json" 
  -d '{"volume_id": "VOL_ID", "mount_path": "/mnt/data"}'

# Detach (by attachment id)
curl -X DELETE https://api.miosa.ai/api/v1/computers/COMPUTER_ID/volumes/ATTACHMENT_ID 
  -H "Authorization: Bearer $MIOSA_API_KEY"

CLI:

miosa volumes create model-weights --size 50
miosa volumes list
miosa volumes attach <id>
miosa volumes detach <attachment-id>
miosa volumes destroy <id>

A local-backend volume lives on one host, so it attaches to computers on that same host. Cross-host attach returns a clear error rather than failing silently.

Mount

A volume is mounted into the runtime instance’s filesystem at a path:

await miosa.services.update(serviceId, {
  volumes: [
    { dataServiceId: volumeId, mountPath: "/var/models" },
  ],
})

At boot, /var/models is the volume’s contents. Writes persist.

Replicas and volumes

Most volumes attach to a single runtime instance. If you scale a service to N replicas, by default each replica gets the same volume mount if it’s marked shared: true, or its own volume if shared: false.

Shared volumes have all the usual concurrency caveats (filesystem locks, file-corruption risk if multiple writers touch the same file). Use Postgres for shared state unless you really know what you’re doing.

Limits

LimitDefault
Max volume size500 GB
Max volumes per project10
Filesystemext4
Host placementMust match the computer host

When to use a volume

Realistic short list:

  1. You’re shipping a self-hosted SQLite-backed app to keep deployment simple.
  2. You’re running an LLM inference service and don’t want to re-download model weights on every instance start.
  3. You have a writable filesystem cache that’s expensive to rebuild.

Anything else, use Postgres or Storage.

See also

  • Overview - the broader data plane
  • Postgres - for relational data (almost always the right answer)
  • Storage - for user-uploaded files

Was this helpful?