gitlab-backup: Back Up and Restore GitLab Projects from the Command Line

Source code: github.com/sgaunet/gitlab-backup

When you self-host GitLab or rely heavily on gitlab.com for your projects, having an independent backup strategy is essential. GitLab’s own backup mechanism works well at the instance level, but sometimes you need something more surgical: back up a single project, or an entire group, on demand, and store the result locally or in S3. That’s what gitlab-backup does.

What started as a quick ops script has grown into a fully-featured CLI suite with backup and restore capabilities, S3 storage support, pre/post hooks, rate limiting, and concurrent group exports.


Features

  • Export a single GitLab project or an entire group recursively
  • Uses GitLab’s native Export/Import API — archives include the full project (repository, wiki, issues, merge requests, labels, and more)
  • Two storage backends: local filesystem or S3-compatible storage
  • Pre/post backup hooks for custom logic (notifications, encryption, etc.)
  • Configurable rate limiting to stay within GitLab API quotas
  • Concurrent exports when backing up a group
  • Companion gitlab-restore tool to restore archives back to GitLab
  • Three configuration methods: YAML config file, CLI flags, or environment variables — with a clear precedence order
  • Distributed as a single binary for Linux, macOS, and Windows

Installation

From GitHub Releases

Download the latest binary for your platform from the releases page.

Homebrew

brew tap sgaunet/homebrew-tools
brew install sgaunet/tools/gitlab-backup
brew install sgaunet/tools/gitlab-restore

Configuration

gitlab-backup supports three configuration methods. Settings are applied in this priority order:

  1. CLI flags (highest priority)
  2. YAML configuration file
  3. Environment variables

Configuration File

The most flexible approach for repeated use. Create a config.yaml:

# debuglevel: "info"
gitlabGroupID: 123       # backup an entire group
# gitlabProjectID: 456   # or a single project
localpath: "/backup"
gitlabtoken:             # or use the GITLAB_TOKEN env var
# gitlaburi: https://gitlab.com
# tmpdir: /tmp
# exportTimeoutMins: 10  # increase for large projects

hooks:
  prebackup: ""
  postbackup: ""

# Optional: store backups in S3 instead of localpath
s3cfg:
  endpoint: "https://s3.amazonaws.com"
  bucketName: "my-gitlab-backups"
  bucketPath: "backups"
  region: "eu-west-1"
  accesskey: ""
  secretkey: ""

Then run:

gitlab-backup -c config.yaml

CLI Flags

Useful for one-off backups or scripting without a config file:

# Back up a single project
export GITLAB_TOKEN=glpat-xxxxx
gitlab-backup --project-id 123 --output /backup

# Back up an entire group
gitlab-backup --group-id 456 --output /backup/groups

# Use a config file but override the timeout
gitlab-backup --config production.yaml --timeout 30

# Back up from a self-hosted GitLab instance
gitlab-backup \
  --project-id 123 \
  --output /backup \
  --gitlab-url https://gitlab.mycompany.com \
  --timeout 60

Available Flags

FlagDescriptionDefault
--config, -cPath to YAML config file(optional)
--group-idGitLab group ID to back up0
--project-idGitLab project ID to back up0
--outputOutput directory for local storage""
--timeoutExport timeout in minutes10
--tmpdirTemporary directory/tmp
--gitlab-urlGitLab API base URLhttps://gitlab.com
--version, -vShow version and exit
--cfgPrint resolved configuration and exit

Environment Variables

All settings can also be provided via environment variables:

GITLAB_TOKEN           # GitLab personal access token (required)
GITLAB_URI             # GitLab base URL (default: https://gitlab.com)
GITLABGROUPID          # Group ID
GITLABPROJECTID        # Project ID
LOCALPATH              # Output directory
EXPORT_TIMEOUT_MIN     # Export timeout in minutes (default: 10)
TMPDIR                 # Temp directory (default: /tmp)
PREBACKUP              # Pre-backup hook command
POSTBACKUP             # Post-backup hook command
S3ENDPOINT             # S3 endpoint URL
S3BUCKETNAME           # S3 bucket name
S3BUCKETPATH           # S3 bucket path prefix
S3REGION               # S3 region
AWS_ACCESS_KEY_ID      # AWS/S3 access key
AWS_SECRET_ACCESS_KEY  # AWS/S3 secret key

Archive Format

Each backup produces a standard tar.gz archive named {projectName}-{projectID}.tar.gz. The archive is generated by GitLab’s native export API and contains the complete project state: repository, wiki, issues, merge requests, labels, and all associated metadata.


Restoring a Backup

The gitlab-restore companion tool restores archives created by gitlab-backup. It validates that the target project is empty before proceeding, then imports the full project via GitLab’s Import/Export API.

Restore from a Local Archive

gitlab-restore \
  --config config.yaml \
  --archive /backup/myproject-123.tar.gz \
  --namespace mygroup \
  --project restored-project

Restore from S3

gitlab-restore \
  --config config.yaml \
  --archive s3://my-bucket/backups/myproject-123.tar.gz \
  --namespace mygroup \
  --project restored-project

Force-Overwrite an Existing Project

gitlab-restore \
  --config config.yaml \
  --archive /backup/myproject-123.tar.gz \
  --namespace mygroup \
  --project existing-project \
  --overwrite   # ⚠️ skips the emptiness check

Restore Process

The restore operation goes through these phases:

  1. Validation — checks that the target project is empty (unless --overwrite is set)
  2. Download — fetches the archive from S3 (if applicable)
  3. Extraction — unpacks the archive to a temp directory
  4. Import — imports the project via GitLab’s Import/Export API
  5. Cleanup — removes temporary files

Requirements:

  • The target GitLab project must already exist (create it via the UI or API first)
  • The token must have Maintainer or Owner permissions on the target project
  • For S3 restores: AWS credentials with read access to the bucket

Going Further: Encrypted S3 Backups

If you need to encrypt your archives before uploading them to S3, the companion project gitlab-backup2s3 combines gitlab-backup with gocrypt to produce encrypted, S3-stored backups in a single workflow.


Development

The project uses Task as its build tool and goreleaser for releases.

task build     # Build the binary
task snapshot  # Create a snapshot release
task release   # Create a tagged release
task doc       # Start a local godoc server
task image     # Build and push the Docker image