> ## Documentation Index
> Fetch the complete documentation index at: https://paper.brimble.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Persistent disk

> Attach durable storage to a project so files survive restarts and redeployments.

Attach durable storage to a project so files survive restarts and redeployments. Without a persistent disk, anything your service writes to the filesystem is lost on every redeploy. The new container starts from a fresh image.

<Warning>
  **Files written outside the mount path don't persist.** Only writes under the configured mount (e.g. `/data`) survive. Anything your service writes elsewhere, the working directory, `/tmp`, the home directory, is gone the moment the container restarts.
</Warning>

Use a persistent disk for:

* SQLite databases (small apps, single-instance).
* File uploads stored to disk before being moved to object storage.
* Cache or state that's expensive to rebuild on cold start.
* Self-hosted tools that need a data directory (Plausible, Umami, n8n, and similar).

## Prerequisites

* A project on a paid plan that includes persistent disks.
* The project should be a single-container service. Persistent disks aren't shared across containers; if you scale beyond one, only one container holds the data.

## Enable a persistent disk

1. Open the project.
2. Go to **Configuration**.
3. Scroll to **Persistent disk** and toggle it on.
4. Set:
   * **Mount path**, the path inside the container to mount the disk at, for example `/data`.
   * **Size**, picked from the dropdown.
5. Save.

<Frame caption="Persistent disk configuration on a project.">
  <img src="https://mintcdn.com/brimble-86/pQAD3e2bSpmJU-dU/images/projects/persistent-disk-section.jpg?fit=max&auto=format&n=pQAD3e2bSpmJU-dU&q=85&s=4d327e5d60e82501718ecf113258330d" alt="The Persistent disk panel under Configuration, showing the toggle on, a mount-path input set to /data, and the size dropdown listing the 10-150" width="1500" height="750" data-path="images/projects/persistent-disk-section.jpg" />
</Frame>

The next deployment provisions the volume and mounts it at the path you set.

## How persistent disks are stored

Brimble persistent disks (for projects and for [sandboxes](../sandboxes/overview)) are backed by **Brimble's globally distributed S3-compatible object storage**, not local SSDs on the host that's running your container. Two practical consequences:

* **Your data survives host failure.** If the host running your project goes down, Nomad reschedules onto another host in the region and the volume reattaches. The disk follows the workload.
* **I/O semantics are closer to networked storage than local disk.** Random write throughput on a persistent disk is lower than what you'd get from a local SSD. For most workloads (SQLite, file uploads, caches) this is fine; for write-heavy databases, use a [managed database](deploy-a-database) instead.

The same model backs sandbox volumes; volumes are interchangeable between projects (`type: web`) and sandboxes (`type: sandbox`) at the surface level, but pick the right `type` when creating a volume so it shows up in the right attach picker.

## Disk sizes and pricing

Disks are available in 10 GB steps from 10 GB up to 150 GB. The default is 10 GB.

Storage bills at **\$0.25 per GB per month** at the base rate. Some regions carry a small multiplier on top of the base rate; the exact monthly cost is shown next to each size in the dropdown.

| Size   | Monthly cost (base rate) |
| ------ | ------------------------ |
| 10 GB  | \$2.50                   |
| 20 GB  | \$5.00                   |
| 50 GB  | \$12.50                  |
| 100 GB | \$25.00                  |
| 150 GB | \$37.50                  |

If you need more than 150 GB, contact support.

## Use the disk

Anything your service writes to the mount path persists across deploys, restarts, and resizes.

```javascript theme={null}
// Node, writing to the mounted disk
import fs from "fs/promises";

const DATA_DIR = "/data";
await fs.writeFile(`${DATA_DIR}/state.json`, JSON.stringify(state));
```

```python theme={null}
# Python
import os, json

DATA_DIR = "/data"
with open(os.path.join(DATA_DIR, "state.json"), "w") as f:
    json.dump(state, f)
```

The mount is empty on first attach. Initialize whatever directory structure your service needs on startup.

## Resize a disk

Disks can grow but not shrink.

1. Open **Configuration → Persistent disk**.
2. Pick a larger size.
3. Save.

The resize happens on the next deployment. The container restarts to pick up the new size; existing data is preserved.

## Limits and constraints

* **Size** caps at 150 GB per project on standard plans. For larger volumes, contact support.
* **One disk per project.** You can't mount multiple persistent disks at different paths.
* **One container per disk.** A persistent disk is a local volume, not a network share. Don't enable autoscaling on a project that depends on a persistent disk for state; only one container will see the data.
* **Region-bound.** A persistent disk lives in the project's region. Moving the project to a different region requires a fresh disk.
* **Backups are your responsibility.** Brimble persists the disk across deployments and host moves but doesn't snapshot it. For data that must survive disaster, copy critical files to object storage on a schedule.

## When not to use a persistent disk

A persistent disk is the wrong choice when:

* **You need scale-out.** Multiple containers reading and writing the same dataset want a managed database or object storage, not a local volume.
* **Your data must be backed up automatically.** Use a managed database (PostgreSQL, MongoDB, etc.); Brimble snapshots those.
* **Your data is large.** Beyond a hundred-ish GB, object storage with a small metadata DB scales better.

For most production apps, the right answer is "managed database for state, object storage for files, no persistent disk." Persistent disks are best for self-hosted tools, prototypes, and edge cases where local files are genuinely the right model.

## Troubleshooting

**Mount path doesn't exist after deploy.** The toggle might be off. Re-check that **Configuration → Persistent disk** is enabled and the path is what you set.

**Files disappear on deploy anyway.** Files written to a path *outside* the mount don't persist. Confirm your code writes under the configured mount path (for example `/data`, not `/var/data`).

**"Permission denied" writing to the mount.** Some images run as a non-root user that doesn't own the mount. In your Dockerfile, ensure the user has access, for example `RUN mkdir -p /data && chown myuser:myuser /data`.

**Resize didn't take effect.** Resizes apply on the next deployment, not in place. Click **Redeploy**.

## Next steps

* [Deploy a database](/projects/deploy-a-database), for state that needs scale-out, backups, and queryability.
* [Builds](/projects/builds), for how the runtime container is built and started.
