Retool's main storage database can grow unexpectedly due to two tables:
- page_saves: stores every autosave of every app. Independent of Git version control. Deleting from Git does not shrink this.
- audit_trail_events: stores audit log events. On self-hosted, retention is manual only.
Before you start
- Take a backup of the main storage DB. Every option below is destructive.
- Test on staging first. Not just backup, actually run the same operation on a non-prod copy.
- For manual DELETEs, run them inside a transaction (
BEGIN; ... COMMIT;) with aCOUNTfirst - that lets you verify the affected row count andROLLBACKbefore committing if anything looks off. - Main storage tables have inter-table dependencies. Only touch what's specifically covered below.
Cleaning up page_saves
Preferred: run the built-in compaction script (self-hosted 3.178+):
./retool_backend --run-pagesave-compaction
Shell into a backend pod and run this. Cloud handles it automatically; self-hosted does not. This deletes page_saves older than 30 days for pages that are archived or deleted 30+ days ago. Respects references in app_metadata, branches, commits, tags, source_control_relationships, and related tables. As a safety measure, even if a save has no references pointing to it, the most recent one is always kept so the current state of the app is never lost.
Optional flag: --concurrency N , ie. --concurrency 4 (controls concurrent DB connections per org, defaults to 1).
Can be run as often as needed. Docs on this here.
Manual cleanup (< self-hosted 3.178 or if you need custom control)
If you use Releases, this is the safe way to proceed:
- Create a new release of your app (this is what you'll benchmark against).
- Join page_saves with the tags table (tags lists all releases per app).
- Decide how far back you want to keep - for example, "everything from the last 2 releases."
- Delete page_saves rows older than the cutoff release for each app.
Deleting a page_save means you cannot restore that specific version/release. Every tagged release preserves the version it points to, which is why release-based cutoffs are safe.
Cleaning up audit_trail_events
The audit_trail_events table is safe to trim as needed. You can delete old rows via a Retool workflow:
Connect your main storage DB as a Retool Postgres resource, then build a Retool workflow that deletes rows older than your chosen retention window on a schedule. This is the most common self-service approach.
Deleted rows are permanent audit history loss.
You can also disable audit logs entirely by setting DISABLE_AUDIT_TRAILS_LOGGING=true which stops new audit events from being written to the storage DB.
Existing rows are untouched - combine with option 1 or manual DELETE to shrink what's already there.
Note that this stops all audit events including sign-ins, permission changes, and query executions and therefore is not appropriate if you rely on audit logs for security/compliance.
Reclaiming physical disk space
Postgres does not immediately return disk to the OS after DELETE. If you specifically need disk reclaimed:
- Standard VACUUM reuses space within Postgres but doesn't shrink the file
- VACUUM (FULL) reclaims disk but takes an exclusive lock (requires downtime)
- pg_repack extension does the same without locking, if installed
Please know that this is Database Administrator territory, not Retool support territory and your infrastructure team should handle this.