# Harbor Garbage Collection: Architecture, Capabilities, and API Usage

> Explore Harbor's garbage collection capabilities for efficient artifact management. Learn how to remove unreferenced blobs and tags with jobs, schedules, and dry-run support.

- Repository: [Harbor/harbor](https://github.com/goharbor/harbor)
- Tags: architecture
- Published: 2026-04-09

---

**Harbor's garbage collection is a job-driven subsystem that removes unreferenced blobs and tags through manual or scheduled runs, with dry-run support, configurable workers, and time-window protection.**

Harbor's **garbage collection** (GC) subsystem in the `goharbor/harbor` repository provides a comprehensive solution for reclaiming storage by removing untagged images and unreferenced layers. Implemented as a first-class job service within the **controller/gc** package, it exposes granular control via the v2.0 system API while maintaining data safety through configurable time-window protections and concurrent execution limits.

## Core Architecture of Harbor Garbage Collection

The GC subsystem follows a layered architecture separating business logic from execution mechanics.

### GC Controller and Policy Model

At the heart of the system lies the **GC controller** ([`src/controller/gc/controller.go`](https://github.com/goharbor/harbor/blob/main/src/controller/gc/controller.go)), which implements business logic for starting, stopping, and scheduling collections. The controller relies on the **Policy model** defined in [`src/controller/gc/model.go`](https://github.com/goharbor/harbor/blob/main/src/controller/gc/model.go), which encapsulates:

- **Deletion flags**: `delete_untagged` and `delete_tag` control whether untagged layers or specific tags should be removed
- **Dry-run mode**: Simulates deletion without removing data
- **Worker concurrency**: Validates 1-10 parallel workers via `validateWorkers`
- **Time-window**: Prevents deletion of recently uploaded blobs

### Job Service Integration

Actual GC execution is delegated to Harbor's **Jobservice** as a job of type `job.GarbageCollectionVendorType`. When triggered, the controller creates an execution via `c.exeMgr.Create` followed by a task through `c.taskMgr.Create` (lines 86-99 in [`src/controller/gc/controller.go`](https://github.com/goharbor/harbor/blob/main/src/controller/gc/controller.go)). This separation allows the controller to manage metadata while the Jobservice handles resource-intensive blob removal.

### Configuration and Time-Window Protection

Safety is enforced through a configurable **time-window** that prevents garbage collection of blobs uploaded within recent hours. The default window of **2 hours** is defined in [`src/common/const.go`](https://github.com/goharbor/harbor/blob/main/src/common/const.go) as `DefaultGCTimeWindowHours`, exposed via `config.GetGCTimeWindow()` in [`src/lib/config/systemconfig.go`](https://github.com/goharbor/harbor/blob/main/src/lib/config/systemconfig.go). This ensures recently pushed artifacts remain available during concurrent operations.

## Harbor Garbage Collection Capabilities

Harbor provides multiple operational modes and safety mechanisms for storage reclamation.

### Manual and Scheduled Execution

**Manual GC** triggers immediate collection via `controller.Start`, accessible through the `/system/gc` API endpoint. For automation, **Scheduled GC** uses Harbor's generic scheduler (`pkg/scheduler`) through `controller.CreateSchedule`, supporting cron expressions for hourly, daily, or custom intervals.

### Deletion Policies

The system supports two primary deletion targets:

- **Untagged images**: Removes layer blobs no longer referenced by any tag when `delete_untagged` is enabled
- **Specific tags**: Allows bulk tag removal via the `delete_tag` flag for large-scale cleanup operations

### Safety Features

**Dry-run mode** executes garbage collection logic without deleting backend storage, enabling administrators to audit what would be removed. Combined with the **time-window protection** (default 2 hours), these features prevent accidental data loss during active development workflows.

### Concurrency and Monitoring

Administrators control resource utilization through the **workers** parameter (1-10), validated by `validateWorkers` in the API handler. Real-time monitoring is available through execution history APIs (`GetGCHistory`, `GetGC`), while `GetGCLog` retrieves detailed task logs for troubleshooting.

## Code Flow for Harbor Garbage Collection

A manual garbage collection run follows this execution path:

1. **API Request**: HTTP POST to `/system/gc/schedule` invokes `gcAPI.CreateGCSchedule` with `ScheduleManual` type
2. **Policy Construction**: `gcAPI.kick` builds a Policy structure, injecting runtime parameters including `redis_url_reg` and `time_window` from system configuration
3. **Execution Creation**: `controller.Start` generates a Jobservice execution via `c.exeMgr.Create` and linked task via `c.taskMgr.Create`
4. **Job Execution**: Jobservice runs the GC worker respecting policy flags (dry-run, workers, deletion settings)
5. **Status Tracking**: Execution metadata and logs are stored in task tables, queryable via `GetGC` and `GetGCLog`

## API Usage Examples

Interact with Harbor garbage collection through the v2.0 REST API.

### Triggering Manual Garbage Collection

Execute immediate collection with custom workers and untagged deletion:

```bash
curl -u admin:HarborSecret \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
        "schedule": {
          "type": "Manual",
          "cron": ""
        },
        "parameters": {
          "delete_untagged": true,
          "delete_tag": false,
          "dry_run": false,
          "workers": 4
        }
      }' \
  https://harbor.example.com/api/v2.0/system/gc/schedule

```

This invokes `gcAPI.kick` → `controller.Start` as implemented in [`src/server/v2.0/handler/gc.go`](https://github.com/goharbor/harbor/blob/main/src/server/v2.0/handler/gc.go).

### Scheduling Recurring Garbage Collection

Create a daily scheduled job using cron syntax:

```bash
curl -u admin:HarborSecret \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
        "schedule": {
          "type": "Daily",
          "cron": "0 0 * * *"
        },
        "parameters": {
          "delete_untagged": true,
          "workers": 5
        }
      }' \
  https://harbor.example.com/api/v2.0/system/gc/schedule

```

The `ScheduleDaily` path in the `kick` function creates a persistent schedule via `controller.CreateSchedule`.

### Monitoring and Managing Executions

Retrieve execution history:

```bash
curl -u admin:HarborSecret \
  "https://harbor.example.com/api/v2.0/system/gc/history?page=1&page_size=20"

```

This calls `gcAPI.GetGCHistory`, which gathers data through `controller.ListExecutions`.

Stop a running job:

```bash
curl -u admin:HarborSecret \
  -X POST \
  https://harbor.example.com/api/v2.0/system/gc/123/stop

```

The `gcAPI.StopGC` handler forwards to `controller.Stop` to abort the Jobservice execution.

Fetch task logs:

```bash
curl -u admin:HarborSecret \
  https://harbor.example.com/api/v2.0/system/gc/123/log

```

`gcAPI.GetGCLog` returns raw log bytes from `controller.GetTaskLog` for debugging failed collections.

## Summary

- Harbor garbage collection operates as a **job-driven subsystem** within `src/controller/gc`, delegating actual work to the Jobservice while maintaining execution metadata separately
- The **Policy model** supports granular controls including dry-run mode, untagged/tag deletion, and configurable worker concurrency (1-10)
- A **time-window protection mechanism** (default 2 hours) prevents removal of recently uploaded blobs via `config.GetGCTimeWindow()` in [`src/lib/config/systemconfig.go`](https://github.com/goharbor/harbor/blob/main/src/lib/config/systemconfig.go)
- Administrators can trigger collections **manually** via `controller.Start` or create **scheduled** runs using the generic scheduler through `controller.CreateSchedule`
- Full **lifecycle management** is available through the v2.0 API, including execution history queries, real-time stopping via `controller.Stop`, and log retrieval through `GetGCLog`

## Frequently Asked Questions

### What is the default time window for Harbor garbage collection?

Harbor implements a **2-hour time window** by default, defined as `DefaultGCTimeWindowHours` in [`src/common/const.go`](https://github.com/goharbor/harbor/blob/main/src/common/const.go). This safety mechanism, exposed through `config.GetGCTimeWindow()` in [`src/lib/config/systemconfig.go`](https://github.com/goharbor/harbor/blob/main/src/lib/config/systemconfig.go), ensures blobs uploaded within the last two hours are excluded from deletion during garbage collection runs.

### Can I run Harbor garbage collection without deleting data?

Yes, Harbor supports **dry-run mode** through the `dry_run` parameter in the GC Policy. When enabled, the system executes all garbage collection logic and reports what would be deleted without actually removing any blobs from storage, enabling safe auditing of reclaimable space.

### How many parallel workers can Harbor garbage collection use?

Harbor garbage collection supports **1 to 10 parallel workers**, validated by the `validateWorkers` function in [`src/server/v2.0/handler/gc.go`](https://github.com/goharbor/harbor/blob/main/src/server/v2.0/handler/gc.go). This concurrency control allows administrators to balance collection speed against system resource utilization by setting the `workers` parameter in the API request.

### Where are Harbor garbage collection logs stored?

Garbage collection logs are stored within Harbor's task management system and retrieved via `controller.GetTaskLog`. Administrators access these through the `/api/v2.0/system/gc/{execution_id}/log` endpoint, which returns raw log bytes from the underlying task manager for troubleshooting specific GC executions.