How to Configure Tag Retention Policies in Harbor: A Complete Guide

Harbor's tag retention policies automatically clean up old image tags using configurable rules defined through the v2.0 REST API or web UI, storing policy definitions in the retention_policy table and executing them via the controller/retention package.

Configuring tag retention policies in Harbor is essential for maintaining a clean container registry and controlling storage costs. The open-source Harbor project (goharbor/harbor) provides a flexible retention engine that evaluates image tags against criteria such as push count and last pull date, automatically removing artifacts that no longer meet your organization's retention criteria.

Architecture of the Retention Policy Engine

Harbor implements tag retention through a layered architecture that separates API handling, business logic, and persistence. Understanding these components helps when troubleshooting or extending retention functionality.

The API layer in src/server/v2.0/handler/retention.go handles HTTP requests for CRUD operations, validates rule syntax, performs permission checks, and triggers executions. The model conversion layer at src/server/v2.0/handler/model/retention.go translates between internal policy.Metadata structs and Swagger API models.

The business logic resides in src/controller/retention, implementing the policy life-cycle including creation, updates, deletions, and asynchronous execution handling. For persistence, the DAO layer in src/pkg/retention/dao/retention.go stores policy definitions in the retention_policy database table.

The frontend UI, built in Vue/TypeScript at src/portal/src/app/base/project/tag-feature-integration/tag-retention/retention.ts, provides a visual wizard for composing rules and monitoring execution status using the same underlying API endpoints.

Policy Structure and Configuration Schema

A retention policy in Harbor consists of several key components that define what to retain and when to evaluate rules.

The algorithm field specifies how rules combine logically—or is the default and most common choice. The scope currently supports only project-level targeting with level: "project" and a ref containing the numeric project ID.

Each policy contains up to 15 rules, where each rule specifies:

  • template: Built-in logic such as latestPushedK, nDaysSinceLastPush, or nDaysSinceLastPull
  • action: Either retain (keep matching tags) or immutable (prevent deletion)
  • params: Template-specific values like count or days
  • tag_selectors: Glob patterns using doublestar syntax to match tag names
  • scope_selectors.repository: Repository-level glob patterns to limit which repositories the rule evaluates

The trigger determines execution timing, supporting kind: "Schedule" with a cron expression or kind: "Manual" for on-demand runs.

Configuring Policies via the Harbor API

While the Harbor web UI provides a visual interface, automating retention policy configuration requires direct API interaction.

Prerequisites and Permissions

Before creating policies, identify your target project ID and ensure you have RBAC permissions on the TagRetention resource. The handler function requireAccess (lines 108-115 in retention.go) validates these rights on every API call.

Creating a Retention Policy

Construct a JSON payload following the schema defined in the internal models. This example retains the 10 most recently pushed tags matching library/** and removes release tags older than 30 days:

{
  "algorithm": "or",
  "scope": { "level": "project", "ref": 42 },
  "rules": [
    {
      "template": "latestPushedK",
      "action": "retain",
      "params": { "count": 10 },
      "tag_selectors": [
        {
          "kind": "doublestar",
          "decoration": "matches",
          "pattern": "**"
        }
      ],
      "scope_selectors": {
        "repository": [
          {
            "kind": "doublestar",
            "decoration": "repoMatches",
            "pattern": "library/**"
          }
        ]
      }
    },
    {
      "template": "nDaysSinceLastPull",
      "action": "retain",
      "params": { "days": 30 },
      "tag_selectors": [
        {
          "kind": "doublestar",
          "decoration": "matches",
          "pattern": "release-*"
        }
      ],
      "scope_selectors": {
        "repository": [
          {
            "kind": "doublestar",
            "decoration": "repoMatches",
            "pattern": "**"
          }
        ]
      }
    }
  ],
  "trigger": {
    "kind": "Schedule",
    "settings": { "cron": "0 0 * * *" }
  }
}

Submit the policy using the v2.0 endpoint. The CreateRetention handler (lines 61-90 in src/server/v2.0/handler/retention.go) validates the rule count, checks for conflicts, and stores the definition:

curl -k -X POST "https://harbor.example.com/api/v2.0/retentions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <TOKEN>" \
  -d @policy.json

The API returns a policy ID and updates the project's metadata with a retention_id reference.

Executing and Monitoring Policies

Trigger a manual execution using the policy ID returned during creation. The TriggerRetentionExecution method processes this request (lines 70-84 in the handler):

curl -k -X POST "https://harbor.example.com/api/v2.0/retentions/123/executions" \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"dry_run":false}'

Monitor execution progress by listing executions and their tasks:


# List all executions for a policy

curl -k "https://harbor.example.com/api/v2.0/retentions/123/executions" \
  -H "Authorization: Bearer <TOKEN>"

# List tasks for a specific execution

curl -k "https://harbor.example.com/api/v2.0/executions/456/tasks" \
  -H "Authorization: Bearer <TOKEN>"

Understanding Rule Templates and Selectors

Harbor provides several built-in rule templates that determine which tags to evaluate:

  • latestPushedK: Retains the most recent K tags pushed to the repository
  • nDaysSinceLastPush: Retains tags pushed within the last N days
  • nDaysSinceLastPull: Retains tags pulled within the last N days

The tag_selectors and scope_selectors use doublestar glob patterns supporting wildcards. The decoration field specifies matching behavior—matches for exact matches or repoMatches for repository patterns. You can include extras parameters to handle untagged images or specific manifest types.

Permission Model and Security Considerations

All retention API operations enforce RBAC through the requireAccess middleware. Users need appropriate permissions on the project resource TagRetention. System administrators can manage policies across all projects, while project members require specific role assignments.

Retention executions run asynchronously with their own task queues, ensuring that large-scale cleanup operations do not block the main API. The execution records maintain audit trails of which tags were evaluated and what actions were taken.

Summary

  • Harbor's retention engine spans multiple layers: API handlers in src/server/v2.0/handler/retention.go, business logic in src/controller/retention, and persistence via src/pkg/retention/dao/retention.go.
  • Policy definitions use JSON structures supporting up to 15 rules with templates like latestPushedK and nDaysSinceLastPull, combined via or logic.
  • Configuration requires a project ID, properly formatted selectors using doublestar glob patterns, and RBAC permissions on the TagRetention resource.
  • Execution can be scheduled via cron expressions or triggered manually through POST /api/v2.0/retentions/{id}/executions, with status monitoring available through the executions and tasks endpoints.

Frequently Asked Questions

What rule templates are available for Harbor tag retention?

Harbor supports several built-in templates including latestPushedK (retain the most recent K tags), nDaysSinceLastPush (retain tags pushed within N days), and nDaysSinceLastPull (retain tags pulled within N days). These templates are defined in the policy metadata definitions within src/pkg/retention/policy and populated in the UI dropdowns defined in retention.ts.

How do I manually trigger a tag retention policy execution?

Send a POST request to /api/v2.0/retentions/{id}/executions with a JSON body containing "dry_run": false (or true for testing). The TriggerRetentionExecution handler creates an execution record and returns a location header pointing to the execution ID, allowing you to monitor progress through the tasks endpoint.

What permissions are required to configure retention policies?

The API enforces RBAC checks through the requireAccess function in src/server/v2.0/handler/retention.go. Users need permissions on the TagRetention resource within the target project. System administrators have global access, while project members need specific roles granted through Harbor's permission system.

Where does Harbor store retention policy definitions?

Policy definitions persist in the retention_policy database table, accessed through the DAO layer in src/pkg/retention/dao/retention.go. When created, policies also store a retention_id reference in the project's metadata, linking the project to its associated retention configuration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →