How to Audit and Clean Up Unused Media Files in Drupal Using Entity Usage and Views

How to Audit and Clean Up Unused Media Files in Drupal Using Entity Usage and Views

Alex Rollin
Alex Rollin
September 3, 2025
Last updated : February 15, 2026
September 3, 2025

If you've been running a Drupal site for more than a year, you probably have a media library problem. Images from old blog posts, PDFs from outdated products, and videos from previous campaigns sit there taking up space. They slow down your backups, clutter your media browser, and make life harder for your content editors.

Our experience shows that most Drupal sites accumulate anywhere from 30% to 50% of completely unused media files within their first three years. One client recently discovered they were backing up 7,000 unused PDFs every night – files that hadn't been referenced anywhere on their site for over two years.

The good news? Drupal provides several effective ways to identify and remove these unused files. This guide walks you through the exact process using the Entity Usage module combined with Views, plus some alternative approaches if you need something simpler or more automated.

Prerequisites

Before you start cleaning up unused media files in Drupal, you'll need:

  • Drupal 10 or 11 (these instructions work for both versions)
  • Composer access to install modules
  • Administrative permissions to configure modules and create Views
  • A recent backup of your database and files directory
  • SSH access to run Drush commands (recommended but not required)

You should also understand basic Views configuration in Drupal. If you've never created a View before, spend 15 minutes with the Views UI first to get familiar with the interface.

Step-by-Step Implementation for Media Cleanup

Step 1: Install Required Modules

Start by installing the Entity Usage module and Views Bulk Operations. These two modules form the foundation of your cleanup process.

composer require drupal/entity_usage drupal/views_bulk_operations
drush en entity_usage views views_ui views_bulk_operations -y

If you want additional cleanup tools, also install:

composer require drupal/unused_media_cleaner drupal/orphans_media
drush en unused_media_cleaner orphans_media -y

Clear your cache after enabling these modules:

drush cr

Step 2: Configure Entity Usage Tracking

Navigate to Configuration > System > Entity Usage or visit /admin/config/system/entity-usage directly.

On this configuration page:

  • Check the box next to Media under "Track usage for these entity types"
  • Enable tracking for any other entity types you want to monitor
  • Save the configuration

Now comes the important part: you need to rebuild the usage tracking database. This process scans your entire site and creates a record of where each media item is currently being used.

Click the "Batch update" tab and then "Recalculate usage". Depending on your site size, this might take anywhere from a few seconds to several minutes.

Step 3: Create Your Unused Media View

This is where things get interesting. You'll build a custom View that shows only unused media items.

Navigate to Structure > Views and click "Add view".

Configure your initial View settings:

  • View name: "Unused Media Audit"
  • Show: Media
  • Type: All
  • Create a page: Yes
  • Page path: /admin/content/unused-media
  • Display format: Table
  • Items per page: 50

Click "Save and edit" to enter the Views configuration interface.

Step 4: Add Essential Fields

In the Fields section, add these fields to give you useful information about each media item:

  • Media: Name - Shows the media title
  • Media: Type - Displays whether it's an image, document, video, etc.
  • Media: Created - When the file was uploaded
  • Media: Thumbnail - Visual preview for images
  • File: URI - The actual file path

For each field, leave the default settings unless you want to customize labels or formatting.

Step 5: Configure the Entity Usage Relationship

This is the critical step that makes everything work.

Under the Advanced section on the right, find Relationships and click Add.

Search for "Entity Usage" and select "Entity Usage: Usage". In the configuration:

  • Leave "Require this relationship" unchecked
  • Apply the relationship

This relationship connects your media items to their usage tracking data.

Step 6: Enable Aggregation and Add Usage Count

Still in the Advanced section, find "Use aggregation" and set it to Yes.

Now go back to Fields and add a new field:

  • Search for "Usage count" (it should appear under the Entity Usage relationship)
  • Configure it to use SUM as the aggregation type
  • Label it "Times Used" or similar

Step 7: Filter for Unused Media Only

Add a filter to show only unused media. Under Filter Criteria, click Add and search for "Usage count".

Configure the filter:

  • Aggregation type: SUM
  • Operator: Is empty (NULL)

This filter ensures you only see media items with zero usage across your site.

Step 8: Add Bulk Operations

To actually delete unused media, add Views Bulk Operations functionality.

Add a new field at the beginning of your field list:

  • Search for "Views bulk operations"
  • Select "Bulk update media"
  • In the configuration, enable only the "Delete media" action
  • Position this field first in your field list

Save your View. You now have a working unused media audit tool for Drupal sites.

Code Examples for Automated Cleanup

Sometimes you need to automate the cleanup process. Here's a custom Drush command that identifies and removes unused media:

getStorage('media');
    
    // Load all media entities
    $media_ids = $media_storage->getQuery()
      ->accessCheck(FALSE)
      ->execute();
    
    $deleted_count = 0;
    $batch_size = 50;
    
    foreach (array_chunk($media_ids, $batch_size) as $chunk) {
      $media_entities = $media_storage->loadMultiple($chunk);
      
      foreach ($media_entities as $media) {
        // Check if media is being used
        $usage = $entity_usage->listSources($media);
        
        if (empty($usage)) {
          // Double-check it's not referenced in old revisions
          if ($this->checkRevisions($media)) {
            continue;
          }
          
          $this->logger()->notice('Deleting unused media: ' . $media->label());
          $media->delete();
          $deleted_count  ;
        }
      }
    }
    
    $this->logger()->success("Deleted $deleted_count unused media items.");
  }
  
  /**
   * Check if media is used in old revisions.
   */
  private function checkRevisions($media) {
    // Add your revision checking logic here
    return FALSE;
  }
}

For a simpler approach, you can create a batch processing script:

/**
 * Batch process to delete unused files.
 */
function custom_cleanup_batch_delete() {
  $batch = [
    'title' => t('Deleting unused media'),
    'operations' => [],
    'finished' => 'custom_cleanup_batch_finished',
  ];
  
  // Get unused media IDs from Entity Usage
  $query = \Drupal::database()->select('media', 'm')
    ->fields('m', ['mid'])
    ->condition('mid', \Drupal::database()->select('entity_usage', 'eu')
      ->fields('eu', ['target_id'])
      ->where('eu.target_type = :type', [':type' => 'media']), 'NOT IN');
  
  $results = $query->execute()->fetchAll();
  
  foreach ($results as $row) {
    $batch['operations'][] = ['custom_cleanup_delete_media', [$row->mid]];
  }
  
  batch_set($batch);
}

/**
 * Batch operation callback.
 */
function custom_cleanup_delete_media($mid, &$context) {
  $media = Media::load($mid);
  if ($media) {
    $context['message'] = t('Deleting @label', ['@label' => $media->label()]);
    $media->delete();
  }
}

Common Mistakes to Avoid

Deleting Without Verification

The biggest mistake people make is trusting the unused media report blindly. Some media might appear unused but actually be:

  • Referenced in custom blocks that Entity Usage doesn't track
  • Embedded using absolute URLs in body fields
  • Used in email templates or external systems
  • Referenced in Views header/footer text areas

Always spot-check a sample of files before bulk deletion. Pick 10-20 files marked as unused and manually verify they're truly not needed.

Ignoring Old Revisions

We've found that Entity Usage sometimes misses references in old node revisions. If you have content moderation enabled or keep extensive revision histories, media that appears unused might still be referenced in previous versions of content.

Before deleting, consider whether you need those old revisions. If not, clean them up first using the Node Revision Delete module.

Not Checking File System References

Some sites reference files directly through their file paths rather than media entities. Run this query to check for direct file references in text fields:

SELECT COUNT(*) FROM node__body 
WHERE body_value LIKE '%/sites/default/files/%';

If you find many direct references, you'll need a different cleanup approach that scans text fields for file paths.

Forgetting About Translations

On multilingual sites, media might be used in translated versions of content that Entity Usage doesn't detect properly. Always test your cleanup process on translated content before running it site-wide.

Running During Peak Hours

Batch deletion operations can slow down your site. Schedule cleanup during low-traffic periods or use queue processing to spread the load over time.

Testing and Verification Steps

Before you delete anything permanently, follow this verification process:

1. Export Your Unused Media List

From your unused media View, export the results to CSV. This gives you a record of what you're planning to delete and allows for manual review.

2. Test with a Small Batch

Select 5-10 unused media items and delete them manually. Then:

  • Clear all caches
  • Check the pages where these media items were previously uploaded
  • Verify no broken images or missing file errors appear
  • Check your logs for any related warnings

3. Verify Entity Usage Accuracy

Teams we work with report that Entity Usage is about 95% accurate out of the box. To verify its accuracy on your site:

  • Pick a media item that shows as "used"
  • Click through to see where it's supposedly being used
  • Visit those pages and confirm the media actually appears
  • Repeat for several media items

4. Check Your Backups

Ensure your backup system is working before any bulk deletion:

# Create a manual backup
drush sql-dump --gzip > backup-before-cleanup.sql.gz

# Verify the backup file size looks reasonable
ls -lh backup-before-cleanup.sql.gz

5. Monitor After Deletion

After removing unused media, monitor your site for 24-48 hours:

  • Check your error logs for missing file warnings
  • Ask content editors to report any missing images
  • Review your 404 reports for attempts to access deleted files

6. Performance Verification

After cleanup, you should see improvements in:

  • Media library loading time (measure before and after)
  • Backup duration and size
  • Database query performance for media-related operations

Document these improvements to justify regular cleanup schedules.

Conclusion

Cleaning up unused media files in Drupal doesn't have to be intimidating. With the Entity Usage module and a properly configured View, you can safely identify and remove unnecessary files that are slowing down your site. The key is to approach it methodically: install the right tools, configure them carefully, verify your results, and always keep backups.

Remember that media cleanup isn't a one-time task. Set up a quarterly review process to keep your media library under control. Your content editors will thank you for the cleaner interface, and your systems administrator will appreciate the smaller backups and faster site operations.

If you're managing a large Drupal site with thousands of media files and need help setting up an automated cleanup process that fits your specific workflow, we can help you build a custom approach that safely identifies unused media while preserving everything your content team actually needs. Our team has experience with complex media migrations and cleanup operations that require careful handling of historical content and multilingual considerations.

Share this article