# Backups

> Part of the NocoDB documentation (Self-hosting > Maintenance). Index of all pages: https://nocodb.com/llms.txt. Any docs page is available as Markdown by adding `.md` to its URL.

URL: https://nocodb.com/docs/self-hosting/maintenance/backups
Last updated: 2026-10-03

Back up a self-hosted NocoDB instance: the Postgres data, the attachments and the config files.

To fully protect your NocoDB instance, back up these three items:

* the **Postgres database** (your data and metadata)
* the **attachments volume** (uploaded files)
* your **config files** (to rebuild the stack quickly)

## What to back up

| Item              | Where it lives                                                 | Why                                                       |
| ----------------- | -------------------------------------------------------------- | --------------------------------------------------------- |
| Postgres database | Bundled: `postgres_data` named volume / External: your DB host | Contains all your bases, tables, rows, users and comments |
| Attachments       | `nocodb_data` named volume (mounted at `/usr/app/data`)        | Files users uploaded to attachment fields                 |
| Configuration     | `docker-compose.yml`, `docker.env`, `nocodb/db.json`           | Lets you rebuild the same stack on a new server           |

<Callout type="note">
  Named volumes persist across restarts and `docker compose down`. But a volume on the same host is not a backup. Always copy database dumps and attachment archives off the server.
</Callout>

## Bundled Postgres

If you used `--pg=bundled` (or the Quickstart compose), back up the database container with `pg_dump`:

```bash
cd nocodb  # your deployment directory
docker compose exec db pg_dump -U nocodb nocodb > backup-$(date +%Y%m%d).sql
```

To restore on a new stack:

```bash
cat backup-20260509.sql | docker compose exec -T db psql -U nocodb nocodb
```

To schedule daily backups, use cron:

```bash
# /etc/cron.d/nocodb-backup
0 3 * * * root cd /opt/nocodb && docker compose exec -T db pg_dump -U nocodb nocodb | gzip > /backups/nocodb-$(date +\%Y\%m\%d).sql.gz
```

## External (managed) Postgres

If you use RDS, Cloud SQL, Azure Database or another managed service, **use the snapshot/backup mechanism of the provider**. Managed providers do this much better than `pg_dump`:

* **AWS RDS**: [Automated backups](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithAutomatedBackups.html) (recommended) + manual snapshots before major upgrades.
* **Google Cloud SQL**: [Automated backups](https://cloud.google.com/sql/docs/postgres/backup-recovery/backups) and on-demand backups.
* **Azure Database for PostgreSQL**: [Backup and restore](https://learn.microsoft.com/en-us/azure/postgresql/single-server/concepts-backup).

For a self-managed external Postgres, run `pg_dump` from a host that can reach your DB.

## Attachments

By default, NocoDB stores attachments on the local filesystem, in the `nocodb_data` named volume. Compose adds the deployment directory name before volume names. Thus, find the real name first:

```bash
docker volume ls | grep _nocodb_data   # e.g. nocodb_nocodb_data
```

Back up the volume with a temporary helper container. The container mounts the volume read-only:

```bash
docker run --rm \
  -v nocodb_nocodb_data:/data:ro \
  -v "$(pwd)":/backup \
  alpine tar -czf /backup/attachments-$(date +%Y%m%d).tar.gz -C /data .
```

If you configured S3-compatible object storage (`NC_S3_*` env vars), your attachments are in that bucket, not in the `nocodb_data` volume. The volume backup above then does not apply. Back up the **bucket** instead, with the tools of your storage provider. For example, enable bucket versioning, lifecycle or cross-region replication rules, or scheduled bucket snapshots.

## Config files

Keep these three files in version control:

```
docker-compose.yml
docker.env
nocodb/db.json
```

If your server is destroyed, restore it in this sequence: provision new server → install Docker → `git clone` your config repo → `docker compose up -d` → restore Postgres dump → restore attachments tarball.

<Callout type="info">
  **Don't commit secrets.** `docker.env` and `nocodb/db.json` contain credentials. Use a private repo, encrypt with `git-crypt` or `sops`, or store secrets separately and template the files at deploy time.
</Callout>

## Restoring on a new server

1. Provision a new Linux VM with Docker.
2. Run the [Single-server install](/docs/self-hosting/installation/single-server) with the same domain settings.
3. Stop NocoDB, so that the database is idle: `docker compose stop nocodb worker`.
4. Restore Postgres: `cat backup.sql | docker compose exec -T db psql -U nocodb nocodb`.
5. Restore attachments into the volume: `docker run --rm -v nocodb_nocodb_data:/data -v "$(pwd)":/backup alpine tar -xzf /backup/attachments.tar.gz -C /data`.
6. Restart: `docker compose start nocodb worker`.

The recovery time depends on the size of your database dump and attachments. A small instance restores in minutes.

---

## Related pages

- [Upgrading](https://nocodb.com/docs/self-hosting/maintenance/upgrading.md): Upgrade a self-hosted NocoDB instance: pull the latest image and restart. NocoDB keeps your data and config.
