DevOpsil

Nexus Repository Cleanup Policies: Stop Your Disk From Filling Up

Dev PatelDev Patel7 min read

Nexus Repository grows silently. Every snapshot build, every Docker pull that caches layers, every npm publish that keeps a pre-release — they all accumulate. Left unmanaged, a Nexus instance that started at 50 GB is routinely at 2 TB within 18 months. By then, cleanup is a painful manual operation, and teams start arguing about what's safe to delete.

The answer is automated cleanup policies configured before the disk fills — not after.

How Nexus Cleanup Works

Nexus cleanup operates in two steps:

  1. Cleanup policy — defines which components to mark for deletion (by age, by last downloaded date, by version pattern)
  2. Task: "Delete unused components" — actually removes the marked components
  3. Task: "Compact blob store" — reclaims disk space after deletion

All three need to be in place. Running the cleanup policy alone doesn't free disk space.

Types of Cleanup Criteria

Nexus supports four cleanup criteria (you can combine them with AND logic):

CriteriaWhat it does
Published beforeComponents published more than N days ago
Last downloaded beforeComponents not downloaded in N days
Release typeApplies to releases, pre-releases (snapshots), or both
Asset name matcherRegex match on asset name/path

The most useful combination for most teams: last downloaded before (e.g., 90 days) combined with release type: pre-releases. This removes snapshots that nobody has fetched recently while keeping anything actively in use.

Configuring a Cleanup Policy via UI

  1. Navigate to Administration → Repository → Cleanup Policies
  2. Click Create Cleanup Policy
  3. Set:
    • Name: maven-snapshots-90d
    • Format: Maven2
    • Release type: Pre-release / Snapshot only
    • Component age: Published before 90 days
    • Last downloaded: Last downloaded before 60 days
  4. Save the policy
  5. Attach it to your snapshot repository: Administration → Repository → Repositories → maven-snapshots → Cleanup Policies tab

Attach the same policy to all snapshot repositories — maven-snapshots, npm-snapshots, etc.

Configuring Cleanup via REST API

For teams managing Nexus as code, use the REST API:

# Create a cleanup policy
curl -s -u admin:password \
  -X POST "https://nexus.example.com/service/rest/v1/cleanup-policies" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "maven-snapshots-90d",
    "format": "maven2",
    "notes": "Remove Maven snapshots not downloaded in 60 days or older than 90 days",
    "criteria": {
      "lastBlobUpdated": "90",
      "lastDownloaded": "60",
      "releaseType": "PRERELEASES",
      "retain": "0"
    }
  }'
# List existing cleanup policies
curl -s -u admin:password \
  "https://nexus.example.com/service/rest/v1/cleanup-policies" | jq '.[] | {name, format}'
# Attach policy to a repository
curl -s -u admin:password \
  -X PUT "https://nexus.example.com/service/rest/v1/repositories/maven2/proxy/maven-snapshots" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "maven-snapshots",
    "cleanup": {
      "policyNames": ["maven-snapshots-90d"]
    }
  }'

Scheduling Cleanup Tasks

Policy attachment doesn't trigger cleanup automatically. You need two tasks:

Task 1: Run the cleanup policy

  1. Administration → System → Tasks → Create task
  2. Type: Repository - Cleanup repositories using their associated policies
  3. Schedule: Daily, 02:00 UTC (off-peak)
  4. Leave repository blank to apply to all repos, or specify one

Task 2: Delete the marked components

  1. Create another task
  2. Type: Admin - Delete unused components
  3. Schedule: Daily, 02:30 UTC (30 minutes after cleanup)

Task 3: Compact blob store

  1. Create a third task
  2. Type: Admin - Compact blob store
  3. Blob store: Select your blob store (usually default)
  4. Schedule: Weekly, Sunday 03:00 UTC

Via REST API:

# Create cleanup task
curl -s -u admin:password \
  -X POST "https://nexus.example.com/service/rest/v1/tasks" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Daily Cleanup - All Repos",
    "type": "repository.cleanup",
    "alertEmail": "[email protected]",
    "schedule": {
      "type": "cron",
      "startDateTime": "2026-03-30T02:00:00",
      "timeZone": "UTC",
      "cronExpression": "0 0 2 * * ?"
    }
  }'

# Create delete unused components task
curl -s -u admin:password \
  -X POST "https://nexus.example.com/service/rest/v1/tasks" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Daily Delete Unused Components",
    "type": "component.deleteUnused",
    "alertEmail": "[email protected]",
    "schedule": {
      "type": "cron",
      "startDateTime": "2026-03-30T02:30:00",
      "timeZone": "UTC",
      "cronExpression": "0 30 2 * * ?"
    }
  }'

Format-Specific Recommendations

Different repository formats accumulate waste differently:

Maven

Maven snapshots are the #1 cause of Nexus disk bloat. Each mvn deploy on a snapshot version creates new artifacts. A busy team can generate 50+ snapshot versions of the same artifact per day.

Policy: maven-snapshots-90d
Criteria:
  - Release type: Pre-release only
  - Last downloaded before: 60 days
  - Published before: 90 days

For Maven releases, be more conservative — releases are often referenced by audits or compliance:

Policy: maven-releases-2yr
Criteria:
  - Release type: Release only
  - Last downloaded before: 365 days
  - Published before: 730 days

Docker

Docker cleanup is more nuanced. Images are built on layers — deleting a tag doesn't delete the layers if another tag shares them. Nexus handles layer deduplication, but you still accumulate orphan tags.

Policy: docker-cleanup-stale-tags
Criteria:
  - Release type: Pre-release (applies to tags matching SNAPSHOT, -rc, -dev, -alpha, etc.)
  - Last downloaded before: 30 days
  - Published before: 60 days

For Docker, also consider using the asset name matcher to target specific tag patterns:

Asset name matcher: .*/.*-SNAPSHOT/.*

This targets only tags with -SNAPSHOT in the name.

Important: After Docker cleanup, blob store compaction is essential — Docker layers are large, and soft-deleted layers don't free space until compaction runs.

npm

npm pre-releases accumulate from CI pipelines publishing -alpha, -beta, and -rc versions:

Policy: npm-prerelease-30d
Criteria:
  - Release type: Pre-release
  - Last downloaded before: 30 days

PyPI

Similar to npm — dev versions (1.2.3.dev4, 1.2.3b1) accumulate quickly in active projects:

Policy: pypi-dev-builds-30d
Criteria:
  - Release type: Pre-release
  - Last downloaded before: 30 days

Monitoring Disk Usage

Before and after setting up cleanup, track blob store size via the API:

# Get blob store metrics
curl -s -u admin:password \
  "https://nexus.example.com/service/rest/v1/blobstores" | \
  jq '.[] | {name, totalSizeInBytes, availableSpaceInBytes}'

Output:

{
  "name": "default",
  "totalSizeInBytes": 1073741824000,
  "availableSpaceInBytes": 214748364800
}

Convert to GB:

echo "scale=2; 1073741824000 / 1073741824" | bc
# 1000.00 GB total, 200.00 GB available — 80% used

Set up an alert when available space drops below 20%. In Prometheus with the Nexus exporter:

# prometheus/alerts/nexus.yaml
groups:
  - name: nexus
    rules:
      - alert: NexusBlobStoreLow
        expr: nexus_blob_store_available_bytes / nexus_blob_store_total_bytes < 0.20
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Nexus blob store {{ $labels.name }} below 20% free space"
          description: "Available: {{ $value | humanizePercentage }}"

Testing Before Full Rollout

Before enabling cleanup policies on production repositories, dry-run against a specific repository:

# Preview what would be cleaned (dry run mode via UI)
# Administration → System → Tasks → Run (preview mode checkbox if available)

# Or check component age manually
curl -s -u admin:password \
  "https://nexus.example.com/service/rest/v1/search/assets?repository=maven-snapshots&sort=lastModified&direction=asc" | \
  jq '.items[:10] | .[] | {path, lastModified}'

This shows the oldest assets in the repository — useful for validating that your policy criteria will target what you expect.

RepositoryPolicyAge thresholdLast downloaded
maven-snapshotsPre-release only90 days60 days
maven-releasesReleases only730 days365 days
docker-hostedPre-release tags60 days30 days
npm-hostedPre-release60 days30 days
pypi-hostedPre-release60 days30 days

Task schedule:

  • Cleanup policies: Daily 02:00 UTC
  • Delete unused components: Daily 02:30 UTC
  • Compact blob store: Weekly Sunday 03:00 UTC

Set these up now, before the disk fills. Retroactive cleanup on a 2 TB blob store with no usage data is a weekend project nobody wants.

Share:

Was this article helpful?

Dev Patel
Dev Patel

Cloud Cost Optimization Specialist

I find the money your cloud is wasting. FinOps practitioner, data-driven analyst, and the person your CFO wishes they'd hired sooner. Every dollar saved is a dollar earned.

Related Articles

Discussion