Old working files

Last updated on
1 October 2026

Imports, conversions and exports often leave scratch folders on disk: extracted archives, intermediate files, per-job status files. Core's temporary-file cleanup only covers managed files, so these stay until someone notices the disk is full. Drupal Cleanup clears them by age, but only in folders a module has explicitly declared, and it moves them into a trash folder next to the run's backup rather than deleting them outright.

Declaring folders

Add a files section to your module's MODULE.drupal_cleanup.yml. Each entry becomes its own task, with the ID working_files:MODULE__KEY:

files:
  mymodule_scratch:
    label: 'My module scratch folders older than 7 days'
    paths:
      - 'public://mymodule/tmp'
      - 'mymodule_scratch'
    max_age: 604800
  • path or paths: stream wrapper URIs, or paths relative to the Drupal root. Paths that don't exist are skipped, so you can list every location your module might use on different hosts.
  • max_age: in seconds, at least 86400 (one day).

What counts as old

Only the direct children of each declared folder are considered: typically one folder per job. Each is judged by the newest modification time anywhere inside it, so a job folder that is still being written to is never touched, however old the folder itself is. Symlinks are skipped and never followed, and anything that can't be fully read is kept.

Paths that are refused

A declaration is reported as misconfigured and does nothing if any of its paths:

  • contains .., or is an absolute path,
  • is the Drupal root, or the root of a stream wrapper (public:// itself),
  • is a symlink, or isn't on the local filesystem,
  • overlaps the backup folder.

Moved, not deleted

Old items are moved into the run's trash folder, next to its backup ({backup folder}/{backup-id}.files/). If the trash is on another filesystem, the item is copied, the copy's size is checked against the original, and only then is the original removed. A failed copy is cleaned up and the original left in place. Each item is checked again just before moving, so one that changed since the run started stays where it is.

  • drush cleanup:restore {backup-id} moves the items back, with their original modification times, as long as nothing now exists at their old location.
  • Deleting the backup (Backups tab, or drush cleanup:backup-delete) deletes its trash folder. Until then, the disk space isn't freed. Backup sizes include moved files, so this is visible on the Backups tab.

Keeping specific items

Implement hook_drupal_cleanup_protected_paths_alter() to keep items that are still needed, for example the folder of a failed job that will be retried:

function mymodule_drupal_cleanup_protected_paths_alter(array &$paths, string $task_id) {
  if (str_starts_with($task_id, 'working_files:mymodule__')) {
    $paths[] = 'public://mymodule/tmp/job-42';
  }
}

An item is kept if it is, contains, or sits inside any protected path.

Running it

drush cleanup:run --task=working_files:mymodule__mymodule_scratch --dry-run
drush cleanup:run --task=working_files:mymodule__mymodule_scratch

It also runs in the cron sweep if enabled.

Help improve this page

Page status: No known problems

You can: