--- title: "Cleanup" sidebarTitle: "Cleanup" description: "Pruning old versions and the files only they referenced." icon: broom keywords: ["cleanup", "retention", "prune", "delete_unverified", "vacuum"] availability: oss: available enterprise: varies summary: >- In the embedded library, `optimize()` removes versions older than a retention window, 7 days by default. A deployment removes old versions in the background only when its configuration enables cleanup, and that configuration sets the retention period; `optimize()` is not available there. --- Every write keeps the version before it, which is what makes [time travel](/management/table#versioning) possible. Cleanup is what ends that -- pruning versions older than a retention window, and the files that only those versions referenced. **Enterprise job type:** `cleanup`. Distinct from `compact` -- compaction merges files, cleanup removes them. `optimize()` in OSS runs both in one call; Enterprise schedules them as separate jobs, and runs cleanup only when the deployment's configuration enables it. ## Retention {#retention} ```python from datetime import timedelta table.optimize(cleanup_older_than=timedelta(days=30)) ``` `cleanup_older_than` defaults to **7 days**. Versions older than that are removed, along with the files only they referenced. On a deployment, the retention period comes from its configuration instead. The latest version is never removed, whatever you pass. `timedelta(0)` makes every older version eligible for removal, but cleanup still keeps the versions that branches and tags protect, as the warning below describes. Pruning is what makes [time travel](/management/table#versioning) finite: an eligible version outside the retention window is gone. Cleanup keeps a version, whatever its age, when it is: - the **latest** version; - a version a **branch** was forked from, along with the files the branch reads; the parent's other old versions are pruned as usual; - a **tagged** version. Under the default policy, a tag can also stop cleanup. When a tagged version is older than the window and is not the latest, cleanup refuses to run: it raises an error naming the tag and prunes nothing. To let it proceed, move the tag to a version inside the window, delete the tag, or widen the window. A tag on the latest version does not stop cleanup. But `optimize()` compacts before it prunes, and compacting commits a new version whenever it merges files, so a tag on what was the latest version can become an older one by the time cleanup runs. `optimize()` then raises after compacting, and its index update does not run. A deployment's background cleanup follows the same rules. If you rely on reading old versions, set the window to cover the range you need before running this, not after. ## Disk usage does not drop immediately {#disk} Compaction writes new, merged files before the old ones are removed, so disk usage can rise before it falls. Space is reclaimed only when cleanup prunes the versions that referenced the superseded files. If you need to reclaim space aggressively in the embedded library, shorten the retention window rather than waiting for the default: ```python table.optimize(cleanup_older_than=timedelta(days=1)) ``` ## Files from failed transactions {#unverified} A write that fails partway can leave files that look like an operation still in progress. Cleanup will not remove them until they are at least seven days old, because it cannot tell them apart from a live write. ```python table.optimize(delete_unverified=True) ``` This option belongs to `optimize()` in the embedded library. A deployment's cleanup jobs never set it. `delete_unverified=True` removes them regardless of age. Only set it when you can guarantee **no other process is writing to the table** -- otherwise it can delete files belonging to a write that is genuinely in progress, and corrupt the table. ## What to read next {#next} Merging small files -- the other half of `optimize()`. The Enterprise jobs that run without a call from you.