How-to guide
Manage storage and disk space
Signals stores every snapshot and query run locally. This guide covers where that data lives, how retention keeps it bounded, how to size the volume, and how to recover when the disk fills up.
Where the data lives
Signals keeps all of its history in a single SQLite database at database.path (default /data/signals.db). Write-ahead logging is on by default (database.wal = true), so alongside the main file you will see a -wal and a -shm sidecar. Every collection cycle appends snapshot rows and query runs to this store, so it grows with the number of targets, the poll cadence, and how long you retain data.
fcntl-style file locking. SQLite expects exactly one writer, and the daemon is that writer. Putting database.path on a network filesystem (NFS, SMB) is not supported: WAL does not work reliably there, and you will see database is locked errors. Keep the database on local disk and let the single daemon own it.How growth is bounded
Retention is what keeps the store from growing forever. Snapshots and query runs older than the retention cutoff are pruned on the daemon's cleanup cycle. You configure it in one of two mutually exclusive ways.
Flat retention
The simplest form is a single cutoff applied to every retention class. The default is 30 days:
signals:
# Flat retention — one cutoff for everything (default 30).
retention_days: 30Structured retention
For finer control you can set per-class cutoffs instead. The structured block and the flat retention_daysare mutually exclusive — set one or the other, never both, or the daemon rejects the config at startup:
signals:
# Structured retention — per-class cutoffs.
# Mutually exclusive with retention_days above.
retention:
short_days: 14
medium_days: 30
long_days: 90retention_days to 0 or a negative value disables cleanup entirely. The daemon warns: "cleanup is disabled — snapshots and query runs will be retained until the daemon disk fills up". Disabled retention is a deliberate choice for setups that prune externally; if you are not pruning externally, leave retention set or the disk will eventually fill.Sizing the /data volume
Size the volume that backs database.pathfor the steady state your retention window implies: roughly the per-cycle write volume multiplied by the number of cycles inside the longest retention class, across all targets, plus headroom for the WAL sidecar and for export staging. Give it slack — SQLite reclaims freed space lazily, so the file does not shrink the instant rows are pruned. A volume that is comfortably larger than the projected steady state avoids the full-disk failure mode below.
Symptoms and recovery for a full disk
When the volume backing the database fills up, writes start failing. The signature is a SQLite error such as database or disk is full on collection or export, and the daemon can no longer persist new snapshots. To recover, bring the store back under the volume size:
- Lower the retention cutoff. Reduce
retention_days(or the structuredretention.*values) so the next cleanup cycle prunes more history. - Grow the volume. If the steady-state size is legitimately larger than provisioned, expand the disk backing
database.path. - Export and offload, then let pruning catch up. Export the snapshots you need for analysis, move the archive off the host, and let the lowered retention prune the local store back down.
If you had disabled cleanup with retention_days <= 0, re-enabling a positive cutoff is the fix — that is the configuration that lets the disk fill in the first place.
The export-memory caveat
See also
For the full set of retention and database options, see the Configuration reference. For the offload step in the recovery flow, see Export snapshots.