npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@liiift-studio/sanity-delete-unused-assets

v2.0.1

Published

Asset cleanup utility for Sanity Studio — remove unused assets, analyze storage, and detect duplicates

Readme

Sanity Delete Unused Assets

npm version license Sanity Studio v3+

An asset cleanup utility component for Sanity Studio that identifies and permanently removes unused assets (images and files no longer referenced by any document) to reclaim storage. It also reports total storage usage and finds duplicate filenames. Built with @sanity/ui.

⚠️ This tool deletes data permanently. Deleting a Sanity asset is irreversible from the Studio. Read the Safety & irreversibility section before running it against a real dataset.

How it works

The component runs a single GROQ query for every image/file asset, counts how many documents reference each one, and treats any asset with zero references as unused. With dryRun it only reports; otherwise it deletes the unused assets in a transaction.

  1. Asset inventory — scans all sanity.imageAsset and sanity.fileAsset documents in your dataset.
  2. Reference analysis — for each asset, counts referencing documents with count(*[references(^._id)]).
  3. Usage detection — any asset with refs == 0 is flagged as unused.
  4. Filter application — applies your assetTypes, olderThan, excludePatterns, and maxAssets options.
  5. Deletion — when not in dryRun, deletes the flagged assets in a batched transaction and reports what was removed.

Features

  • 🔍 Asset scanning — detects unused image and file assets by reference count
  • 📊 Storage analysis — reports file sizes and total/per-type storage usage
  • 🧬 Duplicate detection — groups assets that share the same original filename
  • 🎯 Filtering — narrow the scan by asset type, age, exclude patterns, and a max count
  • 🛡️ Safety controlsdryRun preview, excludePatterns, and batch processing
  • 📱 Sanity UI — built with @sanity/ui, fits naturally inside a Studio tool or pane

Installation

npm install @liiift-studio/sanity-delete-unused-assets

Quick Start

The package's default export is a React component. Render it inside a Studio tool/pane and hand it a Sanity client:

import React from 'react'
import { DeleteUnusedAssets } from '@liiift-studio/sanity-delete-unused-assets'
import { useClient } from 'sanity'

const AssetCleanup = () => {
  const client = useClient({ apiVersion: '2023-01-01' })

  return (
    <DeleteUnusedAssets
      client={client}
      dryRun // preview first — strongly recommended
      onComplete={(results) => {
        console.log(`Cleaned up ${results.deleted} assets, freed ${results.savedSpace} bytes`)
      }}
    />
  )
}

The component is also available as the package's default export, so import DeleteUnusedAssets from '@liiift-studio/sanity-delete-unused-assets' works too.

This package ships a component, not a Studio plugin — there is no auto-registering tool. Mount the component yourself, for example as a custom tool in sanity.config.ts:

import { defineConfig, useClient } from 'sanity'
import { DeleteUnusedAssets } from '@liiift-studio/sanity-delete-unused-assets'

const AssetCleanupTool = () => {
  const client = useClient({ apiVersion: '2023-01-01' })
  return <DeleteUnusedAssets client={client} dryRun />
}

export default defineConfig({
  // ...
  tools: (prev) => [
    ...prev,
    { name: 'asset-cleanup', title: 'Asset Cleanup', component: AssetCleanupTool },
  ],
})

With filters

<DeleteUnusedAssets
  client={client}
  assetTypes={['image']}                 // only image assets
  olderThan={new Date('2024-01-01')}      // only assets created before this date
  excludePatterns={['hero-', 'logo-']}    // skip filenames containing these
  maxAssets={50}                          // never act on more than 50 at once
  dryRun                                  // preview the result without deleting
/>

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | client | SanityClient | required | Sanity client instance (must have delete permissions to actually remove assets) | | assetTypes | ('image' \| 'file')[] | ['image', 'file'] | Which asset kinds to scan | | olderThan | Date | undefined | Only consider assets created before this date | | excludePatterns | string[] | [] | Filename substrings to exclude from deletion | | maxAssets | number | undefined | Cap on how many assets a single run will act on | | batchSize | number | 10 | Number of assets processed per batch | | dryRun | boolean | false | Preview mode — reports what would be deleted without deleting | | onComplete | (results: { deleted: number; savedSpace: number; errors: string[] }) => void | undefined | Called when a run finishes | | onError | (error: string) => void | undefined | Called on a top-level failure |

Safety & irreversibility

Deleting a Sanity asset is permanent. There is no Studio-level undo. Treat every non-dryRun run as destructive and follow these practices:

  • Always run with dryRun first and review the reported list before deleting for real.
  • Export a dataset backup before a real deletion: sanity dataset export <dataset> backup.tar.gz.
  • references() only sees published references. An asset referenced only by a draft document (or via a path/custom resolver that references() does not traverse) can be counted as unused. Such assets may be deleted even though a draft still points at them.
  • Freshly uploaded but not-yet-saved assets have no references and will be flagged as unused — finish your edits before cleaning up.
  • Scope your client. The client you pass controls which dataset is affected and whether deletion is even permitted. A read-only token cannot delete (Sanity returns Insufficient permissions — pass a write token, e.g. via --with-user-token when scripting).
  • Use excludePatterns and maxAssets to limit blast radius on large or unfamiliar datasets.

Dry run

<DeleteUnusedAssets client={client} dryRun />

Preview what would be deleted, validate filters and exclude patterns, and sanity-check storage savings — all without touching your data.

Exclude patterns

excludePatterns={[
  'hero-',   // skip hero images
  'logo-',   // skip logos
  'backup',  // skip anything with "backup" in the filename
]}

Batch processing

Large cleanups are processed in batches (batchSize, default 10) to avoid transaction timeouts on big asset collections.

Storage analysis

The component surfaces storage metrics alongside cleanup:

  • Total storage used by image and file assets, with per-type breakdown
  • Asset counts (total, images, files)
  • Per-asset size and reference count
  • Duplicate filename groups for spotting accidental re-uploads

Performance tips

  • Use batchSize to control how aggressively a run processes.
  • Apply assetTypes / olderThan / maxAssets to reduce scan scope on large datasets.
  • Run large cleanups during off-peak hours.

Requirements

This package declares the following peer dependencies:

| Peer | Supported range | |------|-----------------| | sanity | ^3 \|\| ^4 \|\| ^5 | | @sanity/ui | ^1 \|\| ^2 \|\| ^3 | | @sanity/icons | ^2 \|\| ^3 | | react | ^18 \|\| ^19 |

Regenerating the diagram

The data-flow diagram is generated from a committed Mermaid source (assets/data-flow.mmd):

npm run capture   # renders assets/data-flow.svg via @mermaid-js/mermaid-cli

License

MIT License. Licensed under the terms declared in package.json ("license": "MIT").

Contributing

Contributions are welcome. Please open an issue or pull request on the repository to help improve this utility.