GitLab server-side repository backups to object storage

Server-side repository backups let Gitaly stream Git data straight to object storage instead of the backup archive, which reduces network hops on large instances. This page covers the configuration, trade-offs and checks involved.

On this page

What GitLab server-side repository backups change for large instances

Server-side repository backups let Gitaly send repository data directly to object storage, so the backup host no longer has to pull every Git repository through its own disk and network. On a self-managed GitLab instance with large repositories, the backup task is often slowed by that single pass through the backup host, which also has to hold the archive before it reaches storage. The change concerns where repository data flows, and it leaves the set of backed-up data as it was. Before changing anything, measure whether the backup window or the backup host's network path is the actual bottleneck, because the gain depends on how much Git data moves and how close the backup host sits to the object store.

According to the GitLab backup and restore documentation, the feature is configured on the Gitaly side with object storage access, and the backup command then writes repository backups to that destination. The parts that stay on the standard path matter for planning. The database, configuration files and gitlab-secrets.json are still handled by the normal backup process, and non-repository data stored in object storage falls outside this feature. Confirm in the documentation which object storage types, GitLab versions and Gitaly deployment layouts are supported for your environment, since the supported matrix can change between releases and the exact settings should come from the current version of the docs.

Teams most likely to need this are those whose Git data is large enough that repository backups dominate the window, or whose backup host has limited bandwidth to the object store. Smaller instances rarely gain enough to justify the extra configuration. Before the change, record how long the repository and non-repository phases of the current backup take, document the network path from Gitaly nodes to storage, and test a restore of a server-side backup into a staging instance. Confirm that the restore works on your Gitaly topology, because a backup that cannot be restored into the same layout gives only partial protection.

Configuration options and when each fits

This table compares classic archive-based repository backups, server-side backups streamed to object storage, and server-side backups combined with incremental or split-storage approaches. Read each row as a decision: what the option needs from object storage and Gitaly, and which recovery work it leaves to other procedures. Confirm each option's exact settings against the GitLab backup and restore documentation for your version before choosing.

OptionWhen it fitsWhat it needsWhat it leaves to other procedures
Classic archive-based repository backupsSmaller instances where writing repository data into the backup archive on local or attached storage is within your backup windowEnough local disk for the archive, with transfer from the GitLab host to backup storage handled by your own processObject storage data such as artifacts, LFS, uploads and registry blobs, plus gitlab-secrets.json and gitlab.rb
Server-side repository backups to object storageLarge instances where pushing repository data through the backup archive adds network load and slows the backup windowObject storage target configured for the backup task, and Gitaly able to write to it directly (confirm the exact configuration keys for your version)Object storage data outside the backup command, configuration and secrets files, and testing of restores
Server-side backups with incremental repository backupsInstances where full repository backups no longer finish within the window and the team can manage a chain of backup IDsStored increments that reference a previous backup ID, plus retention that never deletes a link in the chainPeriodic full backups, verification of the chain, and restore order; deleting an increment breaks restores
Server-side backups with split repository storageInstances whose repositories sit across several Gitaly storages and where parallel streaming shortens the windowMultiple Gitaly storages reachable by the backup process, and an object storage layout that keeps each storage identifiableConfirming that every storage is included in the backup run and that restore targets match the storage layout
Geo secondary as a recovery sourceOrganizations needing a warm standby in another region in addition to backupsA Premium or Ultimate tier Geo setup, with replication running continuouslyBackups still required, since Geo replication does not replace a point-in-time archive
Disk snapshots combined with backupsVery large instances where snapshots of the database and file storage are part of the recovery designSnapshot tooling on the infrastructure, and consistent coordination with the database and repository stateConfirming the snapshot procedure against the documented backup guidance and testing restored copies

Setting up server-side repository backups step by step

This sequence takes a self-managed GitLab instance from an unconfigured backup target to a tested repository backup in object storage, with a restore path confirmed before anyone depends on it.

  1. Confirm the GitLab version and edition

    The platform engineer records the exact GitLab version and edition running on the instance and on every Gitaly node, then confirms that the backup and restore plan targets that same version. Server-side backups depend on Gitaly behavior that differs between releases, so the check must come from the installed package, not from memory. Done means a written record of version and edition per node, stored with the change ticket. Confirm the exact behavior for your release in the backup and restore documentation before you go further.

  2. Prepare the bucket and scoped credentials

    The cloud or storage administrator creates a dedicated bucket for repository backups, sets access so that only the GitLab backup process can write to it, and issues credentials limited to that bucket. Decide retention, versioning and encryption settings before the first backup, because changing them later affects every archive already written. Done means the bucket exists, the credentials pass a simple write and read test from a Gitaly host, and the access policy is documented. Ask your storage provider to confirm which object locking and versioning options apply to your setup.

  3. Configure the backup target in gitlab.rb

    The GitLab administrator adds the object storage settings for backups to the configuration file, using the key names listed in the backup and restore documentation for your release, and applies the change with a reconfigure. Keep the file under version control or a documented change record, and store the credential values in your secrets process rather than in plain notes. Done means the reconfigure completes without errors and the settings show in the configuration file exactly as the documentation describes.

  4. Enable server-side backups on the Gitaly side

    The administrator turns on the setting that lets Gitaly stream repository data straight to the bucket, on each Gitaly node that holds repositories, then restarts or reconfigures those nodes as the documentation requires. Check that every storage node has the same settings so no repository falls back to the archive path unexpectedly. Done means each Gitaly node reports the setting as active and the node configuration matches across the fleet. Confirm the exact key and any per-node requirements in the backup documentation.

  5. Run a test backup on a small repository set

    The administrator runs a backup limited to a small, known set of repositories, such as a test group with a few projects of different sizes, so the result is easy to inspect. Record the backup ID, start and end times and any warnings in the command output. Done means the command finishes without failures and the log contains no skipped repositories for the test set. If a repository is skipped or the run falls back to the archive, stop and resolve the cause before repeating the test.

  6. Verify the stored objects and their contents

    The administrator lists the bucket contents for the test backup ID and compares the object names and count against the repositories included in the run. They also check object sizes against the expected repository data and confirm that the backup manifest or metadata for the run is present. Done means every test repository has a matching stored object and the listing is saved with the test record. Ask your storage team to confirm how versioning or lifecycle rules treat these objects.

  7. Rehearse a restore to a separate instance

    The team restores the test backup onto a separate, non-production GitLab instance running the same version and edition, then clones a restored repository and compares commit history with the source. Restore secrets and configuration first, as the restore documentation describes, so that the instance starts cleanly. Done means the restored repositories match the source commit for commit and the rehearsal steps are written down as a runbook. Repeat the rehearsal whenever the GitLab version, storage layout or bucket settings change.

How server-side backups lower network load on large instances

Server-side backups change which host carries repository data. In the default flow, the backup task pulls each repository through the application side, writes it into a backup archive, and then uploads that archive, so each Git byte crosses the network twice. With server-side repository backups, Gitaly streams each repository directly to object storage, and repository data moves from the Gitaly node to the bucket without passing through the backup host. What still crosses the backup host's network is the coordination work and the non-repository parts of the backup, such as the database dump and backup metadata. Confirm the exact flag and task syntax for your version in the GitLab backup and restore documentation before you plan any change.

The size of the gain depends on how much of your backup traffic is repository data and where that data travels. Repository count and total Git data size set the volume that leaves the old path, so an instance with little Git data will see a small difference. Gitaly placement matters as much: a Gitaly node in the same network zone as the bucket moves data over a short, local path, while a node in another region or behind a constrained link sends the same bytes over a longer one. Check whether repositories are spread across several Gitaly storages, because parallel streams from multiple nodes change where the bottleneck sits. Record the bandwidth between each Gitaly node and the bucket before you decide how to schedule backups.

Plan for what this change does not remove. The bucket still stores every backup, so storage capacity, retention and restore time stay the same, and a restore still needs the matching gitlab-secrets.json and configuration files covered by the sibling backup guidance. Ask your cloud provider whether it charges for data egress when Gitaly writes across a network or account boundary, because cross-region traffic can cost more than the bandwidth it saves on the backup host. The network gain may also be smaller than expected if the limit is disk I/O or compression on the Gitaly nodes. Measure one full backup on the existing path and one with server-side streaming in a non-production environment, then record the results in your change log so the restore plan matches the method you use.

Security and operational considerations for backup storage

Server-side backups move repository data into a bucket that holds your full Git history, so the bucket becomes a high-value target in its own right. The cards below cover the decisions the team must make before the first backup runs: who can reach the bucket, how data is protected, how long copies live, and how you know the job worked.

Least-privilege bucket access

Give the Gitaly backup process a credential that can write backup objects under one prefix and nothing else. It should not list other buckets, read artifacts or LFS objects, or change bucket policy. Review the policy after each change to storage settings, and confirm which identity the Gitaly nodes actually use, since a shared administrator key is the most common shortcut.

Separate backup credentials from production

Keep the backup identity apart from the credentials GitLab uses to serve object storage for artifacts, LFS, uploads and the registry. A compromise of the production application should not give an attacker write or delete rights over the backup copies. Ask whether your storage platform can issue a distinct account or role for backups and whether those keys are stored in a separate secrets store.

Encryption in transit

Require TLS on every connection from Gitaly nodes to the object storage endpoint, and reject plain HTTP in the bucket policy where your platform allows it. Check the certificate chain if you use a private or internal endpoint, because a backup client that silently skips verification will pass a test and still expose data on the network.

Encryption at rest

Confirm that the bucket encrypts objects at rest and decide who holds the keys. Provider-managed keys are simpler to operate, while customer-managed keys let you revoke access by disabling the key. Record the key owner and rotation schedule in your backup runbook, and test that a restore still works after a key rotation.

Retention choices the team must make

Set how long each backup generation is kept and how many full and incremental sets remain restorable. Incremental repository backups depend on earlier backups in the chain, so a lifecycle rule that expires an older object can make newer increments unrestorable. Write the retention rule down with the restore procedure, and align it with the recovery point your organization has agreed to.

Immutability and deletion protection

Decide whether backup objects should be protected by object lock or a comparable write-once setting, so that a deleted or overwritten object cannot be removed before its retention period ends. Immutability protects against ransomware and insider mistakes. Confirm with your storage vendor how locks interact with lifecycle rules and whether a locked object can be removed early by an administrator.

Monitoring backup jobs

Alert on failed or missing backup runs, not only on storage capacity. Check that each run writes the expected number of objects, that its size is within a normal range compared with previous runs, and that the completion time falls inside your backup window. Review the job logs after any change to Gitaly or storage configuration, because a silent partial upload can look like success.

Questions teams ask before changing repository backups

What does moving repository backups to object storage cost, and who pays?

Your team or your provider pays for three things: object storage capacity, provider request and transfer charges, and engineering time for configuration and testing. The GitLab backup and restore documentation describes the setting, and the change does not carry a license charge of its own. Storage is the recurring cost. Every backup you keep in the bucket is billed for as long as it is retained, so retention length usually moves the bill more than the configuration work does. Configuration, test restores and handover documentation are one-time costs, although each GitLab upgrade brings a retest. When you request a quote, ask for these items as separate lines: bucket setup, configuration, restore testing, documentation, handover, and whether retention policy and monitoring are included.

How long does a repository backup rollout take?

The duration depends on your instance size, the number of repositories, how many rehearsals run before production, and when your change window opens. This page does not state a duration, so ask for a schedule built from your own environment. The main drivers are the size of your Git data and how long a full backup takes today, because that sets how much measurement you need before and after the switch. Next come the staging rehearsals, usually one for configuration and one for restore. Approval steps and change freeze periods add delay that has nothing to do with the technical work. Finally, a tested rollback path adds time to the plan but reduces the chance that a failed change becomes an incident. Start with a baseline backup run and a measured restore so the schedule rests on measured numbers.

What must our team provide before the change starts?

Before work begins, your team provides the facts that decide the configuration and the test plan. The list below covers the core inputs:

  • The installed GitLab version, edition and install method, since the backup procedure has to match what is running.
  • Object storage buckets in your account, placed in a region that meets your data residency rules, with versioning and lifecycle settings your security team has approved.
  • Credentials for the backup process, scoped to those buckets and stored in your secrets system.
  • A non-production instance with data volumes close to production for rehearsal, plus a production window for the switch.
  • Named owners for approval, restore testing and escalation during the window.

Confirm the exact configuration keys against the backup documentation for your installed version before you write any change request.

Can our own team make this change without a partner?

Yes. A team with Linux administration and GitLab administration experience can make this change using the GitLab backup documentation, a staging instance and a written rollback plan. The work is mostly configuration and verification, so the main question is capacity and evidence. Ask whether someone on your team can read backup logs, run a restore, validate the results and keep the setting correct through upgrades. A partner becomes useful when the team lacks time, when a failed restore on your instance would be costly, or when you need a written record for an assessment. DeployOpen plans, implements, documents and tests self-hosted GitLab inside your own infrastructure under a written scope. You can also choose to keep the change in-house and bring in a partner only for the restore test.

How do server-side backups fit with Geo and disk snapshots?

They protect against different failures, so you usually run all three. GitLab's Geo documentation describes a warm-standby secondary site that is continuously synchronized for disaster recovery, which helps when a whole site is lost. Replication is fast, so a deletion or corruption can also replicate to the secondary. A separate backup archive in object storage gives you a point-in-time copy that is independent of the replication path. Disk snapshots capture a volume at one moment and need coordination with GitLab so the data is consistent. Confirm with the GitLab documentation whether your snapshot procedure needs services stopped or set to read-only in your topology. Schedule backups, snapshots and replication so they do not collide, and test that each method can restore on its own.

What should a restore test prove before we rely on these backups?

A restore test should prove that the backup is complete, that it restores on the GitLab version and edition it came from, and that repositories work afterward. Record how long each phase takes so your recovery estimate comes from evidence. The checks should include:

  • Repository counts and content match the source, confirmed by sampled clones and commit checks.
  • Database, uploads and configuration restore cleanly, with gitlab-secrets.json restored alongside the archive so encrypted data stays readable.
  • Logs show no errors from the object storage read path during the restore.
  • Elapsed time is recorded for the full restore and for each phase.

Keep the results in a dated record. Auditors and the team preparing the next upgrade will both need it.

Does this backup change require a higher GitLab license tier?

The backup configuration does not depend on a license tier, but confirm that against the documentation for your installed version before you budget. The GitLab pricing page lists Free at 0 US dollars, Premium at 29 US dollars per user per month billed annually, and the top tier as custom priced. All three tiers are available for self-managed installations. Your tier decision should follow the features you need, such as advanced CI/CD, priority support, security testing or compliance features, and not the backup change. Keep the two decisions separate in your budget so a tier question does not hold up the storage work, and ask your vendor or partner to confirm the tier for each capability you plan to use.

Do GitLab upgrades change how server-side backups must be run?

Upgrades can change backup behavior, so retest the configuration after each one. GitLab requires upgrades to pass through required upgrade stops. Since GitLab 17.5 these fall at versions x.2, x.5, x.8 and x.11, for example 18.2, 18.5, 18.8, 18.11 and 19.2, 19.5, 19.8 and 19.11, according to the GitLab upgrade paths documentation. Plan a fresh backup and a restore test at each stop you pass, and keep the object storage configuration in version control so it survives reinstalls. Confirm the current stops in the upgrade paths documentation before you schedule any upgrade window, because the stops shape how many rehearsals your plan needs.

Where server-side backups fit in a wider recovery plan

Server-side repository backups change how Git data leaves the instance, but they do not complete a recovery plan. Change the secrets backup first. A repository backup restored onto a rebuilt server is unreadable without the matching gitlab-secrets.json and the gitlab.rb that goes with it. Confirm that secrets and configuration are copied on their own schedule, stored apart from the backup archive and reachable from a clean host. Then run a restore on a scratch server and check that encrypted values such as CI/CD variables and two-factor secrets work, because a successful repository restore will not reveal a missing key.

Next, decide whether incremental repository backups belong in the same change window. Streaming repository data to object storage reduces load on the network path, but it does not remove the dependency chain. Each increment refers to a previous backup ID, so retention rules must keep the full backup and every increment that depends on it. Also confirm what the backup command skips. Artifacts, LFS objects, uploads and registry blobs stored in S3, GCS or Azure need provider versioning or replication, and they will be missing from a restore that only uses the GitLab backup archive. Validate this by restoring a complete chain and opening a sample of repositories, artifacts and uploads.

Treat Geo as a complement to backups, not a substitute. A GitLab Geo secondary provides a warm standby that is continuously synchronized, but it still needs backups for recovery from logical errors and deletions that replicate to the secondary. Before changing the backup path on a site with a secondary, confirm which node runs backups, that replication status is healthy and that the planned failover steps are documented. Test a planned failover and a restore in a non-production environment, then record which recovery path the team uses for each type of incident. The GitLab backup and restore documentation is the reference for the restore procedure that testing should follow.

Running and verifying server-side backups over time

This sequence keeps server-side repository backups trustworthy after the first successful run. It covers routine log and bucket checks, scheduled restore tests, and the configuration review that each planned upgrade stop requires. The output is a backup record your team can show during an incident, an audit or a migration.

  1. Review backup job logs after every run

    A platform engineer reads the output of each scheduled server-side backup job and looks for failed repository transfers, skipped projects and warnings about connectivity to the object storage bucket. Set an alert or a daily review so failures do not wait for a manual check. The step is done when every run has either a clean completion entry or a ticket linked to the failure, and the team can point to the log line that confirms the outcome.

  2. Compare object counts and sizes with the trend

    Open the bucket that receives the repository backups and compare the object count and total stored size with previous runs. A sudden drop often means projects were skipped, while a sharp rise can point to retention settings that are not removing old data. Plot these values over several weeks so the normal growth pattern is visible. The step is done when the team has a documented baseline and a written rule for what triggers an investigation.

  3. Check coverage against the project inventory

    Compare the list of projects on the instance with the set of repositories represented in the latest backup. Pay particular attention to projects created since the last review and to repositories moved between Gitaly storages, because these are the most likely to fall outside a routine check. Investigate any gap before the next backup window. The step is done when the inventory and backup coverage match or every difference has a recorded explanation.

  4. Schedule restore tests on a fixed cadence

    Restore a sample of server-side repository backups into an isolated test instance on a schedule set in the team's recovery policy. Follow the restore procedure in the GitLab backup and restore documentation for the installed version, and include large repositories and projects that sit on different storages. Record how long the restore took and any manual steps needed. The step is done when restored repositories clone successfully, commit history matches the source, and the test write-up is filed.

  5. Plan upgrades around required upgrade stops

    Review the GitLab maintenance policy and the upgrade paths documentation before setting an upgrade window. GitLab requires upgrades to pass through required upgrade stops, which the upgrade paths documentation lists at versions x.2, x.5, x.8 and x.11 for recent releases, so the team maps the route from its current version to the target. Record each stop and the target version in the change calendar. The step is done when the upgrade plan lists every required stop between the current and target versions.

  6. Update backup configuration at each upgrade stop

    Before each required stop, compare the backup-related settings in the GitLab configuration file with the release notes and backup documentation for the target version. Confirm that the object storage connection, the backup target and the Gitaly settings that stream repositories to object storage still match the environment. Apply and test the changes in a staging instance first, then record every difference. The step is done when staging produces a complete backup on the new version and the configuration change is stored in version control.

  7. Retest restores after each upgrade

    Once an upgrade stop is complete, run a restore test against a backup taken on the new version. This confirms that the configuration change works end to end, beyond the backup job finishing without errors. Compare the restored repository list with the source instance inventory and note any differences. The step is done when the post-upgrade restore test passes and its result is attached to the change record.

  8. File evidence for audit and incident review

    Collect log reviews, bucket trend records, restore test write-ups and upgrade change records in one location that operations and security teams can access. Store them with the backup procedure so an auditor or incident lead can see what ran, when it was checked and what was restored. Confirm with your assessor which records they expect. The step is done when the evidence set covers the last full cycle of backups, tests and upgrades, and each review has a named owner.

How DeployOpen works on this

DeployOpen plans and implements self-managed GitLab inside your own infrastructure, including Gitaly server-side repository backups to object storage. We start from your instance size, storage layout and recovery targets, then deliver a configured, tested backup path with written procedures your operators can run.

How we scope

  • Written scope confirms your GitLab version, edition, Gitaly layout and the object storage target before any work starts.
  • We inventory repository storage, current backup schedules, retention rules and the network path between Gitaly nodes and the bucket.
  • Engagements are fixed-scope, with deliverables and timelines agreed in writing; ongoing support is available as a retainer.

How we build

  • We configure the object storage backup target and Gitaly settings in a staging instance, then test them against representative repository sizes.
  • We confirm bucket permissions, encryption, lifecycle rules and credential handling match your security policy before production rollout.
  • We run a full backup and restore test in a separate environment and record backup duration, network load and any errors observed.

How we hand over

  • You receive configuration files, runbooks for scheduled and manual backups, and a restore procedure written for your environment.
  • Documentation covers which backup types go to object storage, what remains in the archive and what your team must still protect separately.
  • We walk your operators through a supervised restore exercise so the procedure is confirmed by the people who will run it.

How we support

  • Retainer support can cover backup monitoring, upgrade planning for GitLab releases and re-testing after configuration changes.
  • We review backup logs and object storage health when you add repositories, change storage nodes or move to a new GitLab version.
  • Ask any partner to confirm response expectations and which upgrade stops apply to your version before signing a retainer.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.