Backs Up
Drupal Cleanup backs up before every delete, with no exceptions. Each run first saves exactly the rows it is about to remove, and only deletes them once that backup has been written and read back successfully. If the backup can't be written, nothing is deleted and the affected tasks report an error. Dry runs change nothing, so they take no backup, and a run that finds nothing to remove leaves no empty backup behind.
Where backups are stored
By default in private://drupal_cleanup/backups. You can change this at Configuration » System » Cleanup, under Backup location, to another stream wrapper URI or an absolute path.
Backups contain raw site data, so these locations are refused:
public://, which is web-accessible,- relative paths, and stream wrappers that aren't available,
- anything inside the web root, including a private file system configured inside it. Web servers such as nginx ignore
.htaccess, so files there may be downloadable by URL.
If your $settings['file_private_path'] is inside the web root (for example sites/default/private), set the backup location to an absolute path outside it, or better, move the private file system out of the web root. Without a usable location, every task reports unavailable and nothing is deleted. The settings page, the Backups tab and drush cleanup:list all say so.
What a backup is
Two files per run:
{id}.jsonl.gz: one line per removed row (task, table, row), gzip-compressed. It is written through Drupal's database API, with no external tools such asmysqldump(tested on MariaDB and SQLite). Binary column values are stored safely.{id}.manifest.json: when it was taken, what triggered it (cron,drush,entity_delete...), who ran it, what each task removed, and the size.
Working-files runs also have an {id}.files/ folder holding the moved items.
Listing and deleting backups
The Backups tab (/admin/config/system/cleanup/backups) lists every backup with its date, trigger, user, what it removed, row count and size, plus the total disk space used. Select backups and choose Delete selected; you are asked to confirm first. The tab needs the Manage Drupal Cleanup backups permission.
With Drush:
drush cleanup:backups drush cleanup:backup-delete 20260930-181500-a1b2c3 drush cleanup:backup-delete 20260930-181500-a1b2c3,20260930-191500-d4e5f6 drush cleanup:backup-delete --older-than=30There is deliberately no download link in the admin UI: backups hold raw data, and anyone who needs one has server or Drush access.
Backups and the hold
While cleanup is on hold, backups cannot be deleted from the Backups tab or with Drush, and automatic pruning stops. Restoring still works. See Compliance and records retention for the hold switch and the audit log, which records every backup deletion, pruning and restore.
Keeping backups for a set time
Delete backups older than (days) on the settings page is 0 by default, which keeps backups until you delete them. Set a number to have cron delete older backups automatically. Remember that working-files backups hold the moved folders, so on a busy site with a full disk, a retention period is worth setting.
Restoring
drush cleanup:restore 20260930-181500-a1b2c3 --dry-run drush cleanup:restore 20260930-181500-a1b2c3- Rows are re-inserted table by table. Rows whose key already exists are skipped, so restoring twice is safe.
- A table that no longer exists is reported and skipped.
- Moved working files go back to their original location, with their original modification times, unless something now exists there.
- The dry run shows how many rows the backup holds per table and changes nothing.
Restore inserts row by row, so a very large backup (hundreds of thousands of rows) can take a few minutes.
Upgrading
Updating Drupal Cleanup (for example with composer update drupal/drupal_cleanup) only replaces the module's own folder. Nothing you or other modules set up is stored there:
| What | Where it lives | Touched by an update? |
|---|---|---|
| Table, queue and folder declarations | each declaring module's own MODULE.drupal_cleanup.yml |
No |
| Settings (enabled tasks, cron interval, limits, backup location, retention) | the site's active configuration, in the database | No |
| Backups | the backup location (default private://drupal_cleanup/backups) |
No |
The module's default settings are only read when it is first installed.
- The declaration format is stable. If a future version changes it, the old format keeps working for at least one major version and is reported as deprecated in
drush cleanup:list. A declaration the module can't read makes its task misconfigured; it never deletes based on a misread declaration. - Settings are carried over. Any renamed or restructured setting comes with an update that moves your value across, so run
drush updatedbafter updating, as with any module. A missing setting falls back to its documented default. - Backups stay restorable. A newer version can restore backups taken by an older one.
Keep declarations in your own module, never inside the drupal_cleanup folder itself: that folder is replaced on every update.
Uninstalling
Uninstalling Drupal Cleanup removes its settings but leaves its backups in place, since they may be the only copy of what was removed. Delete them from the Backups tab first if they aren't needed.
Related sites
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion