A project called “test” is not always a test project. It may hold the container image a staging server still pulls, an issue someone promised to revisit, or a deploy key quietly used by a weekend job. That is why this is not a click-by-click deletion tutorial until much later. First we are going to make the project earn the word disposable.
GitLab now gives most deletions a recovery window, which is helpful—but it is not a substitute for understanding dependencies or preserving data. On GitLab.com, a project marked for deletion is normally retained for 30 days. Self-managed administrators can configure their own retention period, and an Owner can choose a second, permanent-deletion action while the project is pending.
Maybe deletion is not the action you need
Archive when the project should become read-only but remain available for reference.
Transfer when the code and collaboration history belong under another namespace on the same GitLab instance.
Change visibility or membership when the problem is excessive access rather than the project’s existence.
Rename when the project is active but misleadingly named.
Delete only when the project and its dependent resources should enter retirement together.
The repository is only one room in the project
Deleting a GitLab project removes the project container and related resources, including repository history, issues, and merge requests. Before proceeding, inventory everything that refers to the project or lives inside it.
Walk the dependency perimeter
Repository branches, tags, Git LFS objects, submodules, forks, mirrors, and wiki history.
Open issues, merge requests, discussions, releases, milestones, boards, snippets, and uploaded design files.
CI/CD schedules, triggers, variables, job artifacts, environments, deployments, runners, and downstream pipelines.
Container images, package registry artifacts, Terraform state, secure files, Pages sites, and release assets.
Webhooks, integrations, deploy keys, project access tokens, service accounts, badges, status checks, and security policies.
External deployment manifests, package consumers, bookmarks, documentation, status pages, DNS, monitoring, and local Git remotes.
Export useful project data—but read the exclusions
GitLab project exports preserve many collaboration objects and repositories, but GitLab explicitly says export files should not be treated as backups. Availability and exact contents depend on the GitLab version and offering.
Commonly exported data includes project and wiki repositories, uploads, issues, merge requests, comments, labels, milestones, releases, LFS objects, boards, and some archived pipeline information.
Not exported includes package and container registry images, CI/CD job traces and artifacts, CI/CD variables, triggers, webhooks, encrypted tokens, secure files, job-token allowlists, and several security or approval settings.
Only the latest merge-request diff and latest pipeline are preserved in an export/import workflow according to GitLab’s documented limitations.
Export compatibility is version-sensitive; an untested archive can fail exactly when the original project is gone.
Store exports and separately preserved secrets in access-controlled, encrypted storage with a retention owner and deletion date.
To request an export, open Settings → General, expand Advanced, find Export project, and start the export. Wait for completion, download the archive, record the source GitLab version, then test an import into an isolated destination where it cannot run untrusted CI against valuable variables.
Give the Git repository its own portable recovery point
git fetch --all --prune
git bundle create ../project-before-deletion.bundle --all
git bundle verify ../project-before-deletion.bundle../project-before-deletion.bundle is okay
The bundle contains these 3 refs:
... refs/heads/main
... refs/tags/v1.0.0
... HEAD
The bundle records a complete history.What the word “complete” does—and does not—mean here
git fetch --all --prunecontacts configured remotes and updates remote-tracking references; review those remotes before trusting their coverage.git bundle create ... --allstores every ref present in this local repository, including local branches and tags.git bundle verifychecks prerequisites and connectivity for the Git objects in the bundle.“Complete history” describes the bundled Git refs. It says nothing about GitLab issues, LFS objects not present locally, registries, artifacts, variables, or external systems.
The command sequence was validated with Git 2.43.0 against a disposable repository. The abbreviated refs in the displayed output are illustrative.
A backup becomes believable only after a restore drill
git clone project-before-deletion.bundle recovery-check
git -C recovery-check log -1 --oneline
git -C recovery-check tag --listCloning into 'recovery-check'...
f37666d Recovery point
v1.0.0The drill should answer questions, not just exit zero
git cloneproves another repository can be reconstructed from the bundle.git logchecks the expected recovery commit;git tag --listchecks named release refs.Compare important branches, tags, submodules, large files, and build inputs with the original project.
Perform a separate GitLab import drill for issues and collaboration history, and independently restore every export exclusion the project needs.
The local validation restored a branch and tag from a temporary bundle and then removed the entire fixture.
Write a deletion record someone else can understand
Exact GitLab host, namespace, project name, path, numeric project ID, and current visibility.
Business owner, technical owner, requestor, approver, and person performing deletion.
Reason for retirement and why archive, transfer, or access changes were insufficient.
Dependency review results and the owners who confirmed each downstream migration.
Locations, checksums, encryption, access, and tested restore results for retained data.
Deletion date, expected permanent-deletion date, retention window, and a named person responsible for restoration decisions.
Schedule deletion only after the review is signed off
Sign in with the intended account and open the exact project.
Compare its namespace, project name, URL path, and project ID with the approved deletion record.
Confirm you have the Owner role and that project deletion is permitted.
On the project overview, open the Actions menu and select Delete.
Read the dialog again, enter the requested project name, and select Yes, delete project.
Confirm the project shows a pending-deletion state, record the scheduled deletion date, and notify affected owners.
The first action queues a background job that marks the project for deletion. Scheduled CI/CD pipelines stop running while the project is marked. On GitLab.com the normal delay is 30 days; self-managed retention may differ, so the date shown by your instance is authoritative.
Use the recovery window as a control, not a countdown
If a missed dependency appears, open the project’s Actions menu and choose Restore before permanent deletion. GitLab requires the Owner role. Verify that repository access, schedules, integrations, Pages, deployments, and consumers actually recover; a restored project page alone does not prove the wider system is healthy.
Permanent deletion is a second decision
A project already pending deletion can expose Delete permanently in its Actions menu. Selecting it, entering the project name, and confirming removes the project and related resources immediately. GitLab moved this capability to the Free tier in version 18.0, but instance policy and offering can still affect what you see.
After the project disappears, work is still left
Confirm the project URL no longer exposes private data and record the final state.
Remove or rotate credentials, deploy keys, project access tokens, webhooks, runner assignments, and external secrets that existed for the project.
Update submodules, dependency manifests, documentation, catalogs, dashboards, alerts, deployment jobs, mirrors, and local remotes.
Apply the approved retention policy to exports and bundles; “keep forever just in case” is not a data-governance plan.
Watch dependent systems through at least one normal operational cycle and record unexpected requests for the retired resource.
When the Delete action is missing or nothing happens
No Delete option: confirm you have Owner access and that administrators or group settings allow Owners to delete projects.
Project is archived: GitLab can still offer deletion, but verify you opened the intended archived project and not an active namesake.
Project remains pending: that is expected during the configured delay. Record the displayed date rather than repeatedly triggering actions.
Project unexpectedly restored: check whether the scheduling user left, was downgraded, or lost access before the deletion job ran.
Deletion failed on self-managed GitLab: administrators can inspect background-job and project deletion errors; do not keep clicking permanent deletion without understanding the failure.
Path cannot be reused: redirects, retained records, or pending deletion can block immediate reuse. Do not make path reuse the reason to bypass recovery controls.
The best deletion is uneventful
Nothing pages you. No student loses a semester’s work, no production deployment asks for a vanished image, and nobody discovers that “backup” meant only the default branch. That quiet ending is not luck. It is the result of treating deletion as a small recovery exercise with a delete button at the end.
Comments and corrections