A Python CLI tool to find and delete old CI/CD job artifacts across all projects in a GitLab group. Helps free up storage by cleaning up artifacts that are no longer needed.
- Scan entire groups — Find all old artifacts across every project in a GitLab group
- Subgroup support — Optionally include all subgroup projects
- Configurable age threshold — Only target artifacts older than N days (default: 14)
- Two-step workflow — First scan (read-only), then delete (with confirmation)
- JSON export — Scan results exported to timestamped JSON for audit trails
- Subgroup URL export — Utility script to export all subgroup URLs
- Rate limiting — Automatic retry on GitLab API rate limits (429)
- Pagination — Handles large groups with many projects and jobs
gitlab-artifacts-cleaner/
├── app/
│ ├── gitlab_client.py # Shared GitLab API client
│ ├── find_old_artifacts.py # Scan & export old artifacts to JSON
│ ├── clean_old_artifacts.py # Delete artifacts from JSON report
│ └── export_subgroup_urls.py # Export subgroup URLs to text file
├── config/
│ └── settings.py # Configurable settings
├── output/ # Generated files (gitignored)
├── .env.example # Environment variables template
├── requirements.txt
├── LICENSE
└── README.md
- Python 3.8+
- A GitLab instance (gitlab.com or self-hosted)
- A GitLab Personal Access Token with
read_api+apiscopes
git clone https://github.com/cegape/gitlab-artifacts-cleaner.git
cd gitlab-artifacts-cleaner
pip install -r requirements.txtcp .env.example .envEdit .env:
GITLAB_BASE_URL=https://gitlab.com
GITLAB_TOKEN=your-personal-access-tokenEdit config/settings.py to change the default age threshold:
DAYS_THRESHOLD = 14 # artifacts older than 14 daysScan all projects in a group and export old artifacts to JSON (read-only):
python app/find_old_artifacts.py --group my-orgWith subgroups:
python app/find_old_artifacts.py --group my-org --include-subgroupsCustom age threshold:
python app/find_old_artifacts.py --group my-org --days 30Generates: output/find_old_artifacts_YYYY-MM-DD_HH-MM-SS.json
Pass the JSON file from Step 1 to delete the artifacts. You will be prompted to type YES before any deletion:
python app/clean_old_artifacts.py output/find_old_artifacts_2026-02-11_14-30-00.jsonUtility to export all subgroup URLs of a group:
python app/export_subgroup_urls.py --group my-org
python app/export_subgroup_urls.py --group my-org --include-parent| Flag | Description |
|---|---|
--group |
(required) GitLab group path |
--include-subgroups |
Include projects from subgroups |
--days N |
Minimum artifact age in days (default: 14) |
--quiet / -q |
Suppress real-time output |
| Argument | Description |
|---|---|
json_file |
(required) Path to JSON file from find_old_artifacts.py |
| Flag | Description |
|---|---|
--group |
(required) Parent group path |
--include-parent |
Include the parent group in the output |
--out FILE |
Output file (default: output/subgroup_urls.txt) |
| Guard | Description |
|---|---|
| Two-step workflow | find_old_artifacts.py is read-only; clean_old_artifacts.py requires explicit YES confirmation |
| Age threshold | Only artifacts older than the configured threshold are targeted |
| Audit trail | Scan results are saved as timestamped JSON files in output/ |
| Rate limit handling | Automatic retry with backoff on API 429 responses |
This project is licensed under the MIT License.