Skip to content

Why the FUTO Notes server data directory grows

The FUTO Notes server’s data directory grows with your edit history, not only with the number of notes. Every time a changed note syncs, the app uploads a new encrypted copy, and the server keeps the version it replaces for 365 days. Deleted notes are kept for 365 days too. Cleanup runs every 6 hours and removes versions once they pass those limits.

What is in the data directory

futo-notes-data/
db/notes.db SQLite: notes list, versions, sessions, wrapped vault key
db/notes.db-wal recent database changes (see backups)
db/notes.db-shm
blobs/<user-id>/<blob-id>

Each blob is one file: one encrypted version of one synced file, a note or an image. The server cannot read them and knows only their size. The database stays small. Almost all of the space is in blobs/.

To see how much each part uses:

sudo du -sh futo-notes-data/db futo-notes-data/blobs
sudo find futo-notes-data/blobs -type f | wc -l

A self-hosted server has no storage quota. The limit is your disk.

How long blobs are kept

The server tracks every blob in a ledger, and a blob’s state decides when it can go:

StateWhat it meansWhen it is deleted
StagedUploaded, not yet attached to a note24 hours after upload, if nothing claims it
ClaimedThe current version of a noteNever, while the note exists
RetainedA version that was replaced by a newer one, or the last version of a deleted note365 days after it was replaced or deleted
PurgeableBelonged to a vault that was deletedAt the next cleanup
Legacy sharedA duplicate reference left by the old TypeScript serverNever automatically

Old versions stay readable so a device can still fetch a version it last saw, for example as the common starting point when merging edits two devices made at the same time. These lifetimes are part of the sync protocol and cannot be configured; BLOB_RETENTION_DAYS from the old server is ignored.

The row for a deleted note also stays in the database as a small marker, so other devices learn about the delete.

When cleanup runs

The server runs its jobs on a fixed schedule, counted from when it starts:

  • 1 minute after start, both schedules run once.
  • Every hour, expired sign-in sessions are removed.
  • Every 6 hours, three maintenance jobs run in order: storage reconciliation, expiry of old retry records, and blob garbage collection.

Restarting the server restarts the clock, so maintenance also runs a minute after every start. There is no setting for the schedule, and BLOB_GC_INTERVAL_MS is ignored.

Each job logs one line when it finishes, for example:

level=INFO msg="storage reconciliation" summary="adopted 0, skipped 0, cap hit false"
level=INFO msg="blob GC" summary="purged 14 rows, removed 14 files"

Storage reconciliation

Storage reconciliation walks BLOB_DIR looking for files the ledger has no record of, for example a blob whose upload was interrupted. It adopts each one as staged, which gives the app the usual 24 hours to claim it, after which garbage collection deletes it. It adopts at most 500 files per pass and picks up the rest 6 hours later.

Files that are not under a valid user-ID folder, or whose folder names a user the database does not know, are skipped and logged, never deleted.

Warning: Don’t put your own files inside blobs/<user-id>/. Anything there that the database does not know about is adopted and then deleted about a day later.

Turn off garbage collection with BLOB_GC_ENABLED

Set BLOB_GC_ENABLED=false to stop the server deleting any blob file. In a Docker install it goes in .env; run docker compose up -d afterwards.

With it off, reconciliation and session cleanup still run, and blobs still move between states, but nothing is removed from disk and the data directory only grows. It is meant for times when you want nothing deleted: while you investigate a problem, or right after a restore, until you are sure the server is pointed at the right database.

When you turn it back on, eligibility is worked out from timestamps, so the first pass removes everything that expired while it was off.

Getting space back

Space comes back on its own as retained versions reach 365 days. The server has no command to purge old versions sooner or to compact storage. If the data directory is larger than you expect, large images and notes that are edited constantly are the usual reason: each synced change adds a full new copy.

Next steps