# Docker disk usage and cleanup
URL: https://synquic.tech/docs/guides/docker-cleanup.md

See what fills a server's disk (images, containers, volumes and build cache, with the project each belongs to), clean it up safely from the server's Docker tab, and schedule the cleanup so it runs by itself.

import { Step, Steps } from 'fumadocs-ui/components/steps';

Every build leaves images and build cache behind, and over months a server's disk fills up. Synq shows what uses the
space on each server and removes what is safe to remove. It never touches anything that belongs to Synq, to your
projects or to the Synq install itself, whatever you select.

## See what uses the disk

Open **Servers**, pick a server and choose the **Docker** tab. **Docker disk usage** reads the same data as
`docker system df -v` on that server:

- Four totals at the top: **Images**, **Containers**, **Volumes** and **Build cache**, each with its size, how much
  is **reclaimable**, and how many there are and how many are in use.
- Below them, one list per category, largest first: **Name**, **Size**, **Belongs to** and, for containers and
  build cache, **State**. Long lists show the biggest items first, with **Show all** to expand.
- **Measured** tells you when the numbers were read. Press **Refresh** to read them again.

**Belongs to** names the owner when Synq can tell: **Project: `<name>`**, **A Synq project** (one you can't see),
**Synq control plane**, **Synq**, **Compose stack: `<name>`**, or **Nothing identifies an owner**.

A badge marks every item a cleanup will never remove:

| Badge | Why it is protected |
| --- | --- |
| **Control plane** | Part of the Synq install: its API, dashboard, edge, Postgres and Redis containers, their images and volumes. |
| **Managed by Synq** | Has a Synq label or name, is a Synq image, or is a container Synq keeps for release history. |
| **Project data** | A volume a Synq service declares (read from Synq's database, so it counts even while the service is stopped and its container is gone), or a volume a Synq container mounts. |
| **Kept for rollback** | An image of an active release, or one Synq keeps so you can roll back. |
| **In use** | An image some container was created from, a volume any container references (stopped ones included), a running container. Anything Synq can't check counts as in use. |

## Clean up by hand

Only **instance administrators** see **Clean up**. Other users can read the disk usage.

<Steps>

<Step>

### Choose what to remove

Press **Clean up**. In **Clean up Docker**, tick the categories:

| Option | Default | What it removes |
| --- | --- | --- |
| **Dangling images** | On | Untagged image layers that no container uses. |
| **Unused images older than N days** | Off, 14 days | Tagged images that no container uses. They are downloaded again when needed. |
| **Stopped containers not managed by Synq** | Off | Exited or never-started containers created outside Synq. |
| **Build cache** | On | All unused build cache. The next build takes longer. |
| **Unused volumes** | Off | Volumes that no container references. |

</Step>

<Step>

### Review the exact list

Press **Review what will be removed**. Synq lists every image, container and volume it would remove, with the
reason (**Dangling image**, **Unused image**, **Stopped container**, **Unused volume**), the total ("12 items,
about 3.4 GB"), the build cache it would prune, and how many items the protection rules kept.

</Step>

<Step>

### Confirm volumes, if any

When the list contains volumes, tick **I understand that the listed volumes and their data will be deleted
permanently**. Read the list first: a volume from an app you run outside Synq holds real data.

</Step>

<Step>

### Remove

Press **Remove**. The result says how many items were removed and how much space was freed, and how many were
skipped or could not be removed.

</Step>

</Steps>

Removal is careful by design:

- Synq plans again at the moment you press **Remove** and removes only items that are **still** selected **and**
  were on the list you reviewed. Anything that became used or protected in between is skipped.
- Items are removed one at a time and never forced, so Docker itself refuses anything that is in use.
- The build cache prune runs last and removes all **unused** build cache.
- The cleanup is recorded in the [audit log](/docs/guides/audit-log) as **Docker cleanup**, with the removed items
  and the bytes reclaimed.

<Callout title="Volumes hold data" type="warn">
Removing a volume deletes its data permanently. Volumes of Synq projects, services and databases, and of the
control plane, are always kept, even when stopped. Unused volumes are never selected unless you tick the option.
</Callout>

## Schedule the cleanup

Instance administrators also see **Scheduled cleanup** on the Docker tab. It is **off by default**.

1. Turn on **Run on a schedule**.
2. Set **Schedule (cron)**, in server time. The default `41 3 * * 0` runs on Sundays at 03:41.
3. Choose the **Servers**: **All servers**, or **Selected servers** and tick **Include this server** on each server
   you want (the list is shared by every server's Docker tab).
4. Under **What it removes**, pick the same categories as above.
5. Press **Save**.

**Next run** and **Last run** show the schedule's state. **Open in Jobs** opens the system job **Docker cleanup**,
where every run is recorded with its output, and where you can press **Run now**. A scheduled run removes everything
its fresh plan selects, with the same protections: nothing Synq owns, nothing in use, never forced.

<Callout title="Two other cleanups already run" type="info">
Synq has two more built-in jobs that are on by default: **Deployment artifact cleanup** removes old release
images of your projects beyond what their retention keeps, and **Docker build-cache garbage collection** keeps the
build cache on each Docker host within about 10 GB, every night. The Docker cleanup is for everything else. See
[Scheduled jobs](/docs/guides/jobs).

A [build server](/docs/guides/build-servers) keeps no release images: each image is removed there once it reaches
its deploy server. If a restart interrupts that hand-off, the deployment artifact cleanup removes the leftover
image from the build server after 6 hours.
</Callout>

## From the API and AI agents

| Call | Needs | What it does |
| --- | --- | --- |
| `GET /api/system/servers/:id/docker/disk-usage` | `server:read` | Read the disk usage, owners and protections. |
| `POST /api/system/servers/:id/docker/cleanup/preview` | `server:admin` and instance authority | The exact list a scope would remove. Removes nothing. |
| `POST /api/system/servers/:id/docker/cleanup` | `server:admin` and instance authority | Remove the confirmed items from a preview. |
| `GET /api/system/docker-cleanup/schedule` | `settings:read` and instance authority | The schedule, scope and servers. |
| `PUT /api/system/docker-cleanup/schedule` | `settings:admin` and instance authority | Change them (`serverIds: null` means all servers). |

The same routes are MCP tools, so an agent can check disk usage (`get_system_servers_by_id_docker_disk_usage`) and,
with enough access, run a cleanup. See the [Servers API](/docs/api/servers) and [System API](/docs/api/system).

## Limits

- If Synq can't read the release history of some project, it offers **no images** at all, since any image might be
  that project's rollback target. Containers, volumes and build cache are unaffected.
- Only Docker objects are cleaned: files on the host, logs and bind-mounted folders are not.
- Removing the build cache or unused images makes the next build or pull slower.

## Related guides

<Cards>
  <Card title="Servers" href="/docs/dashboard/servers" description="Every tab of a server's page." />
  <Card title="Scheduled jobs" href="/docs/guides/jobs" description="System jobs, including Docker cleanup." />
  <Card title="Persistent storage" href="/docs/guides/persistent-storage" description="How project volumes are kept." />
</Cards>
