For the complete documentation index, see llms.txt. This page is also available as Markdown.

Permanent removal

How to permanently prune a Team, Workspace, Project or Dataset: archive first, remove permanently as root, and understand how storage is actually reclaimed.

Regular removal in Supervisely is reversible — a removed Project or Dataset goes to the Trash Bin and can be restored. Permanent removal is the second, irreversible step: it drops the entity from the database and releases the storage behind it.

This page explains the model, the API methods for every level, and — most importantly — why disk usage does not drop to its final value the moment a removal finishes.

The two-step model

Removal is always two steps, at every level:

  1. Archive — a soft, reversible removal. The entity disappears from the UI and moves to the Trash Bin. Any user with sufficient permissions can do this.

  2. Remove permanently — a hard, irreversible removal. Only a root (instance administrator) user can do this.

Permanent removal only accepts entities that are already archived. If you call it on a live entity, the request is rejected — archive it first.

Level
Step 1 — archive (soft)
Step 2 — remove permanently (root only)

Team

teams.archive

teams.remove.permanently

Workspace

workspaces.archive

workspaces.remove.permanently

Project

projects.archive

projects.remove.permanently

Dataset

datasets.archive

datasets.remove.permanently

projects.remove and datasets.remove still work as deprecated aliases of projects.archive and datasets.archive. Prefer the *.archive names in new integrations.

API reference

All methods live under /public/api/v3/ on your instance and authenticate with the x-api-key header. See the API reference for full schemas.

Method
Request body
Returns

teams.archive

{"id": 42}

teams.remove.permanently

{"teamsIds": [42, 43]} — max 50 ids

{"taskId": 987}

workspaces.archive

{"id": 7}

workspaces.remove.permanently

{"workspacesIds": [7, 8]} — max 50 ids

{"taskId": 988}

projects.archive

{"id": 111}

projects.remove.permanently

{"projects": [{"id": 111}], "preserveProjectCard": false}

datasets.archive

{"id": 222}

datasets.remove.permanently

{"datasets": [{"id": 222}]}

instance.data.cleanup-unused

— (root only)

{"taskId": 989}

Team and Workspace removal runs in the background

teams.remove.permanently and workspaces.remove.permanently return a task id immediately and then drain in the background. A single team can hold thousands of projects, files and job artifacts, so the work is deliberately asynchronous.

What this means in practice:

  • The Team or Workspace disappears from the UI as soon as the call returns.

  • The actual database and storage work continues afterwards. Poll tasks.info with the returned taskId to follow it.

  • When the task reaches finished, that entity's own data is gone.

  • If a removal fails, the task reaches a terminal error status — it does not retry forever. Inspect the task, resolve the cause, and call the method again (see idempotency below).

Project and Dataset removal is synchronous — the call returns when the entity is gone.

How storage is actually reclaimed

This is the part worth understanding before you measure your bucket.

Image and video data on a Supervisely instance is stored instance-globally and reference-counted by content hash. One stored object can be referenced from any number of Projects, Workspaces and Teams — that is what makes cloning a project cheap and what stops duplicate uploads from consuming space twice.

Because of that, permanently removing an entity drops its references to the data, not the data itself. The underlying objects are reclaimed once nothing references them any more and a grace window has passed. This happens in two waves:

Wave 1 — inline, during the removal. Data whose last request is older than REMOVE_IMAGE_REQUESTED_THRESHOLD (12 hours by default) is reclaimed as part of the removal itself. Recently-requested data is deliberately left alone, so that an in-flight download or an open labeling session is not pulled out from under it.

Wave 2 — the unused-data garbage collector. Everything left over is swept by the instance-wide GC, which runs on a daily schedule and can also be triggered on demand with instance.data.cleanup-unused (root only). The GC applies a 3-day grace window before reclaiming an unreferenced object, and it also cleans up orphaned figure geometries left behind by removed annotations.

What each level reclaims

Every level releases the data belonging to the entities nested inside it, plus its own artifacts:

  • Team — Team Files (teams_storage), labeling materials, python notebooks, task files, custom data, export archives, and labeling job debug backups. Plus everything in its Workspaces.

  • Workspace — models and checkpoints (models/archives). Plus everything in its Projects.

  • Project / Dataset — images, videos, point clouds and volume slices (images/original, videos, point_clouds), per-video metadata folders (videos_meta), mask and mesh geometries (figures/geometries), README images (assets/projects/images) and labeling job debug backups (debug_backups/jobs).

Example: pruning a Team end to end

The recipe below archives a Team, removes it permanently, waits for the background task, and then triggers the garbage collector to release the shared data.

Step 1. Archive the Team

Step 2. Remove it permanently

This call requires a root user and returns a task id.

teamsIds and workspacesIds accept up to 50 ids per call. Split larger cleanups into batches.

Step 3. Poll until the task finishes

Repeat until status is finished. A status of error is terminal — the removal stopped and will not resume on its own.

Step 4. Reclaim the shared data

Once the removal task is finished, the Team's references are gone. Trigger the garbage collector to sweep whatever is now unreferenced — or simply wait for the daily run.

Remember that the GC honours the grace windows described above: objects requested within the last 12 hours, and objects that became unreferenced less than 3 days ago, are intentionally left for a later run. Running the cleanup twice in a row will not shorten those windows.

Projects and Datasets

Projects and Datasets follow the same archive-then-remove sequence, and the Python SDK exposes dedicated helpers for them.

When passing a list of ids to remove_permanently, all ids must belong to the same Team — group them before calling.

Notes and limitations

  • The admin Team (id 1) cannot be removed. Attempts to archive or permanently remove it are rejected.

  • Permanent removal is idempotent. Ids that are already removed are silently skipped, so it is safe to retry a batch after a partial failure or a task that ended in error.

  • Only archived entities can be removed permanently. The one exception is projects.remove.permanently with preserveProjectCard: true — see below.

  • preserveProjectCard: true is a different operation. Instead of deleting the project, it keeps the project card in place and drops only its data. Use it when you want to retain the project's identity, history and place in the UI while releasing its storage. Because the project itself survives, this variant does not require the project to be archived first.

See also

Last updated