Why GitLab restores fail on version and edition mismatches
A GitLab restore only works when the target instance runs the same GitLab version and the same edition (Community or Enterprise) as the instance that produced the backup, and when the gitlab-secrets.json file from that same installation is restored with it. Teams hit this rule during incident recovery, when a server rebuild is forced by hardware or OS failure, and when they move an instance to new infrastructure. In each case the person running the restore is often working from memory or from a half-documented runbook, which is where mismatches start. The Linux package, the Helm chart, the GitLab Operator and Docker installs all depend on the matching package or image version, so the restore target has to be prepared from the backup's version, not from whatever is newest.
Plan the restore target before anything is lost. Record the exact GitLab version, edition and package or image tag for every backup, store the version metadata alongside the archive, and keep the matching installer available in a location you control, since you may not be able to download it during an outage. For air-gapped or offline environments, this package mirror is part of the recovery plan, not an afterthought. Install the matching version on the new host, confirm the edition, then restore gitlab-secrets.json before running the restore so encrypted database values can be read. A restore that skips the secrets file can appear to succeed and still leave CI variables, two-factor secrets and runner tokens unusable.
Treat the restore procedure as something you test, not something you read. Run a restore into a scratch environment on a schedule, using a backup taken from production and the same version pinning your recovery would use, then check repositories, users, CI variables and container registry access. Keep the GitLab backup and restore documentation as the authoritative reference for each release, and confirm steps against it before every test, because restore prerequisites change between versions. Ask your vendor or implementation partner to walk through the version pinning, secrets handling and test evidence in writing before you rely on the plan for an incident or migration.
The restore sequence: packages, secrets, then data
This sequence rebuilds a self-managed GitLab instance on a target host that matches the source version and edition, so the restored data loads onto a compatible application and the encrypted values it depends on come back intact.
Record the source version and edition
Before any restore, the operator records the exact GitLab version, the edition (Community or Enterprise) and the installed package build from the source instance, and stores them alongside the backup archive. Confirm them by reading the version from the running instance and matching it against the package metadata, not from memory or a ticket. The step is done when the version string, edition and backup timestamp are written in the restore runbook and the backup file name matches that timestamp.
Mirror the matching package into your own repository
The team places the exact package for the recorded version and edition in an internal package repository or artifact store that the target network can reach, since an air-gapped or locked-down environment may not reach public mirrors during an incident. Keep the package checksum with it. Confirm the mirrored file's checksum matches the value published for that build before anyone relies on it. Also confirm that your restore procedure will not pull a newer minor or patch release by accident during installation.
Install the same version and edition on the target
On the target host, the operator installs the same GitLab version and edition from the internal mirror, using the installation method the team has standardized on. The restore target must match the source exactly, because the backup format and database schema are tied to that release. Do not run the instance yet. The check is that the installed version and edition, read from the package, match the values recorded in step one.
Restore gitlab-secrets.json and gitlab.rb first
Before restoring data, the operator copies the source gitlab-secrets.json and the gitlab.rb configuration file onto the target, keeping file ownership and permissions. Without the secrets file, encrypted database values such as CI variables, tokens and two-factor secrets cannot be read after the data returns. Compare the SHA-256 checksum of the restored secrets file with the checksum recorded on the source host. The step is done when the checksums match exactly.
Restore the backup archive
The operator runs the backup restore task against the archive from the recorded backup, after stopping the services that write to the database as the restore procedure directs. Restore only the archive that matches the recorded version and edition, and keep the original archive untouched. The step is done when the restore task completes without errors and its output names the expected backup timestamp. Confirm the archive's version metadata matches the target before running it.
Run reconfigure and start services
The operator runs the reconfigure command so the restored gitlab.rb is applied to the target, then restarts GitLab and checks that all components report healthy. Review the reconfigure output for warnings about missing secrets or changed settings before moving on. The step is done when the instance starts cleanly and the component status check shows no failing services.
Verify login, clone and pipeline behavior
The team confirms functional restore with a named test account logging in through the restored authentication settings, a clone of a representative repository over HTTPS and SSH, and a read of a recent issue or merge request. They also confirm that a CI variable or runner registration still works, which tests that the secrets file was restored correctly. Record the results in the runbook. The restore is complete when these checks pass, and any failed check is investigated before users are switched to the target.
Restore target options and when each fits
This table compares the GitLab install methods you might use as a restore target and the situations each suits. Read each row against your own platform standards, then confirm method-specific restore steps with GitLab before you commit to a layout.
| Restore target | What it suits | Restore considerations | Confirm before choosing |
|---|---|---|---|
| Linux package | Teams running GitLab on VMs or bare metal who want the most mature install path | Bundles PostgreSQL, Redis and Sidekiq, so the restored host carries the same package version as the backup source | Exact package pinning and the restore sequence for your version |
| Helm chart | Teams that already run Kubernetes and want GitLab components as cluster workloads | Stateful services and storage classes need their own restore plan, separate from the chart release | Whether your chosen backup method supports the chart and how the chart version maps to your backup |
| GitLab Operator | Kubernetes teams that prefer operator-managed lifecycle and upgrades | Restore steps depend on how the operator manages the custom resource and its data volumes | Operator-specific restore documentation and version compatibility with the backup archive |
| Docker | Smaller or test instances where a container image is the standard deployment unit | Image tag must match the backup's GitLab version and edition exactly, including volume mapping | Image tag, edition and volume layout required for restore |
| Source installation | Organizations with strict build control that need to compile every component themselves | Highest manual effort to keep component versions aligned with the backup | Dependency versions and the exact restore procedure for your build |
| Same host rebuild | Recovery after host failure where the original hostname and network identity can return | Restores onto a clean install of the same version and edition, then needs the original secrets file in place | Whether the original OS and package versions are still available to reinstall |
| New host rebuild | Migration to new hardware, a new cloud account or a new network zone | Hostnames, certificates and runner registration change, and the external URL must be set before restore | DNS, TLS and runner re-registration steps for the new address |
| Cloud Native Hybrid layout | Large deployments where stateless components run on Kubernetes and PostgreSQL and Redis run on VMs or managed services | Stateful services are restored outside the cluster, then stateless components are pointed at them | Which database and Redis restore procedures apply to your managed or VM services |
When a restore needs an upgrade and how upgrade stops affect it
When the backup was taken from the same GitLab version and edition as the target instance, the restore is the simplest case. The packages on the rebuilt server must match the version recorded when the backup was made, so no upgrade step is needed after the restore. This is the case most teams should rehearse first, because it isolates the restore procedure from upgrade behavior.
- Pin the exact package version: Record the full version string of the source instance and install the same package on the target before restoring anything.
- Match the edition: Community Edition packages cannot restore Enterprise Edition data, so confirm the edition on both sides.
- Restore secrets before data: The
gitlab-secrets.jsonfile must be in place before the restore runs, or encrypted data will not be readable. - Keep the configuration aligned: Compare
gitlab.rbon the target with the source so that external URL and storage settings match. - Reconfigure and check after restore: Run the reconfigure and health checks, then confirm a sample of projects, pipelines and users.
Before relying on this path, confirm the restore steps and version requirements for your exact release in the GitLab backup and restore documentation.
An older backup restored onto a newer release is where upgrade stops matter. GitLab requires upgrades to pass through required upgrade stops, which since GitLab 17.5 fall at versions x.2, x.5, x.8 and x.11, for example 18.2, 18.5, 18.8, 18.11, 19.2, 19.5, 19.8 and 19.11. A backup cannot be restored directly onto the newest release if the path skips a stop, so the restore target must be planned as a sequence of installs.
- Identify the backup version: Read the version in the backup metadata and the package used to create it.
- List every stop in between: Map each required stop between the backup version and the intended target.
- Restore onto the first stop: Bring the data up to the first required version, run its post-upgrade steps, then move to the next stop.
- Avoid skipping: Do not jump over a stop because the intermediate package is inconvenient to obtain.
- Plan the time: Each hop needs its own package, validation and rollback point, so the number of stops drives the effort.
Confirm the path for your versions in the GitLab upgrade paths documentation before scheduling any restore.
A restore that doubles as a migration, such as moving to new hardware, a new operating system or a different install method, combines restore rules with upgrade rules. The source and destination may differ in package layout or in where stateful services run, so the path from the backup version to the destination version must still follow documented stops. Treat the migration as a restore rehearsal first and a cutover second.
- Separate the two changes: Restore the same version onto the new platform first, verify it, then upgrade in a second step.
- Check the install method: Confirm the target install method is supported for the version you are restoring.
- Keep the source intact: Retain the original instance and its latest backup until the destination passes verification.
- Document each stop: Record the version, date and validation result at every stop for change records.
- Rehearse the full path: Run the complete sequence on a non-production copy to measure its length.
For the exact stops and any platform-specific limits, confirm with the upgrade paths documentation and your own environment.
Whichever situation applies, the restore plan should name the backup version, the target version and every documented stop between them before the change window opens. Writing the path down turns a version question into a checklist that an operator can follow under pressure. It also gives auditors and change managers evidence that the restore followed a documented sequence rather than an improvised one.
- Write the sequence: List backup version, each required stop, and final target with the package used at each step.
- Assign rollback points: Decide where a snapshot or verified backup is taken before each hop.
- Test the path, not only the restore: Include upgrade steps in the rehearsal and time them against your change window.
- Store the plan with the backup: Keep the version map beside the backup catalog so it survives staff changes.
- Review before each hop: Re-check the upgrade paths documentation at the start of each restore because stops are defined by release.
Before you commit to a path, confirm the stops and their order in the GitLab upgrade paths documentation and in the backup and restore guidance for your release.
What to test before an incident or migration
A restore that finishes without errors can still leave people locked out and pipelines idle. The six areas below check the restored system from the outside in, so each one catches a different failure that a successful restore command would miss.
Scheduled test restore
Restore the latest backup archive into an isolated environment on the same GitLab version and edition as production, on a fixed schedule. Record the restore duration and the GitLab version reported after the restore. A backup you have never restored into a clean host is an assumption, not a recovery option. Confirm the package version matches exactly, because a mismatch fails the restore before any data is checked.
Secrets and configuration validation
Confirm that gitlab-secrets.json and gitlab.rb from the same point in time are in place before the first start of the restored instance. Without the matching secrets file, encrypted database values such as two-factor secrets and CI variables cannot be read, and the instance may appear healthy while those features fail. Check that the external URL and SSH settings point at the new environment.
Repository and CI pipeline checks
After the restore, clone a sample of repositories across projects, groups and storage shards, and confirm that branches, tags and merge request history are present. Trigger one pipeline per representative project to confirm that the .gitlab-ci.yml definitions, variables and artifacts resolve. Repository data alone does not prove the pipelines that depend on it still run.
Authentication and sign-in
Test sign-in with each method your users rely on, including SAML, LDAP, OmniAuth providers and two-factor authentication, using test accounts with the same group memberships as production. Confirm that SCIM-provisioned users and group sync still map to the right roles. A restored instance that loads but rejects every corporate login is one of the most common outcomes of a rushed recovery.
Runner reconnection and registration
Check that existing runners reconnect to the restored instance and that new runners can register with a fresh token. Confirm that runner and GitLab major and minor versions remain aligned, since a runner built for a different version may fail in ways that look like network problems. Test one job on each executor type you operate, including autoscaling executors that depend on cloud credentials.
Attachments, artifacts and timed run-book review
Open a sample of issue attachments, job artifacts, LFS objects and package or registry items, and confirm checksums where your storage supports them. Items kept in object storage may not be in the backup archive at all, so confirm where each category lives. Then run the recovery run book start to finish with a stopwatch and the people who will execute it, and record every step that needed guessing.
Why restoring secrets first prevents a broken instance
Restore the secrets file before you restore any data. The gitlab-secrets.json file holds the keys that GitLab uses to encrypt certain database values, including two-factor authentication secrets, CI/CD variables and some integration tokens. The database backup stores those values in encrypted form, so a restore that brings back the data but not the matching keys leaves the instance running with values it cannot decrypt. The failure often appears late, when a user, pipeline or integration hits a broken value, which makes it easy to misdiagnose as a data problem. Plan the order so the secrets file, gitlab.rb and the installed package version are in place before the database import begins.
The same order applies to the rest of a full rebuild. gitlab.rb carries the settings that the package reads at reconfigure time, such as the external URL and storage paths, so it must match the source instance's layout before you run reconfigure. SSH host keys matter for Git over SSH: if they change, developer clients will warn about a changed host identity, so keep the original host keys with the rest of the configuration. TLS certificates and private keys belong in the same restore set. Confirm with your own team which of these files your instance uses and where each is stored, because the list depends on how you deployed it.
The detailed procedure for backing up and restoring these files, including file permissions and where to store copies, is covered in the sibling topic on backing up GitLab secrets and configuration. For this topic, the decision is sequencing: confirm that the secrets and configuration backups exist and match the archive you plan to restore, then include a secrets-restore step in every restore rehearsal. A rehearsal that skips this step will not show the failure you are trying to prevent.
Security and operational considerations for restore media
Backup archives and the secrets file are the two items that let a restore succeed or expose your data. The cards below cover how to protect them, who may run a restore, and where to test before an incident. Together they turn the version and edition rules into a controlled procedure.
Protect archives and the secrets file
A GitLab backup archive holds repositories, database content and other instance data, and the secrets file holds keys that decrypt data stored in the database. Store both under encryption and restrict read access to a small group of administrators, and keep the two in separate locations so one leak does not expose everything. Confirm with your backup tooling how encryption is applied, since it is not a default you can assume. Check that copies made off-site follow the same rules.
Keep restore packages in a trusted repository
A restore must run on the exact GitLab version and edition that created the backup, so the installation package for that version is part of the recovery evidence. Mirror the packages you need into a repository you control, record the version string next to each backup, and verify package checksums before installing. Without a local copy, a restore can stall if the public package location is unavailable during an incident.
Separate the test environment from production
Restore tests should run on an isolated host that cannot send email, trigger runners, or reach production integrations. Disable outbound webhooks and mail delivery in the test copy, and use separate credentials for any connected service. This prevents a rehearsal from changing live projects, pipelines or user notifications, and it gives you a safe place to check the restored data before anything is cut over.
Log restore activity as change evidence
Every restore attempt should leave a record: who started it, which backup and version were used, which configuration files changed, and whether the instance passed its checks afterward. Keep these records with your change management system so auditors and incident reviewers can trace what happened. Ask your team which logs capture the restore commands and where they are retained before you rely on them.
Limit who can run restores
Restoring an instance overwrites data and can expose it to whoever holds the backup, so restore rights should sit with a named, small group of administrators. Require a second person to approve the backup selection and target version before a production restore begins. Review that access list on a fixed schedule and after staff changes, because a restore is one of the most sensitive operations an administrator can perform.
Roll out restore configuration changes gradually
The GitLab hardening guidance is a work in progress and recommends applying changes gradually rather than all at once. Apply this to restore configuration as well: change one setting at a time in the test copy, confirm the instance still starts and passes checks, then promote the change to production. Record each step so that if a restored instance behaves differently, you can identify which change caused it.
Restoring GitLab backups: questions teams ask before hiring help
Can a GitLab Free backup be restored onto a Premium instance?
A backup restores onto the same GitLab version and the same edition it came from, so the answer depends on the rule you follow rather than on the tier you pay for. Moving a backup between editions is a separate migration task, not a restore step. Premium is listed at 29 US dollars per user per month billed annually on the GitLab pricing page, but a license change does not alter the rule for restoring a backup. Confirm the exact upgrade procedure for your source and target editions in the GitLab backup and restore documentation before you plan the move.
What determines the cost and effort of planning restore tests?
The main drivers are the number of GitLab nodes, the size of the database and Git data, whether repositories and artifacts sit in object storage, and how many environments must be rehearsed. A single-node instance with local storage is a small exercise. A multi-node reference architecture with Gitaly, PostgreSQL and Redis needs a plan for each component. Fixed-scope work is quoted from a written scope that lists the environments, the restore targets and the evidence you want to keep. DeployOpen does not publish a price list, so ask for a quote that names each deliverable.
How long does a GitLab restore take, and what drives the duration?
Restore duration depends on the backup size, the speed of the storage and network it reads from, the number of repositories, and whether the restore must reconfigure and reconcile services afterward. Restore time is the variable you measure in your own environment, because no duration is published for every instance. Rehearse the restore on hardware that resembles production, time each step, and record the result. The GitLab backup and restore documentation describes the steps that you should time.
What does a restore project need from our internal team?
Expect to provide access to the source and target environments, a named owner for the gitlab-secrets.json and gitlab.rb files, the current backup inventory, and someone who can approve maintenance windows. Your team also decides which version and edition the restored instance must run, because that choice comes before any restore step. Internal staff should review the runbook and sign off on the evidence from each rehearsal. Ask the provider which of these tasks they perform and which stay with your team.
Can our own engineers run test restores without outside help?
Yes, a team with Linux administration experience can run test restores if it keeps the same GitLab version and edition, restores the secrets file first, and records each step. The work is repeatable, so a team can build a checklist and rehearse it on a regular schedule. Outside help is most useful when the instance is large, uses object storage or Geo, or when the restored system must pass a compliance review. Compare the internal effort against the scope you would otherwise buy, and confirm the upgrade stops with the GitLab upgrade paths documentation if the target version differs from the backup.
How does the restore procedure change for a different install method?
The restore rules stay the same, but the commands and file locations change with the install method. The Linux package, the Helm chart, the GitLab Operator, Docker and source installs each handle services and configuration differently. Restoring onto Kubernetes also requires a stateful layer outside the cluster, because the reference architectures do not support PostgreSQL or Redis inside Kubernetes. Check the GitLab installation methods page and confirm each step against the method you run before you write the runbook.
Do restore tests need to repeat after every GitLab upgrade?
Yes, the restore should be rehearsed again after any version change, configuration change or change to the backup tooling. A backup made on one version cannot be restored onto a different version under the same-version rule, so the rehearsal must match the version you run today. Plan the retest into your upgrade calendar, and check the GitLab maintenance policy for the current stable release schedule. Ask any provider to include a retest in the written scope when upgrades are part of the engagement.
How DeployOpen plans and tests GitLab restores
DeployOpen starts every restore plan by fixing three facts about the instance: the exact GitLab version that wrote the backup, the edition and tier in use, and the install method (Linux package, Helm chart, GitLab Operator, Docker or source). The same-version, same-edition rule means the restore target must run the identical GitLab version and edition as the source, so the plan records the installed package version on both sides and confirms that the replacement host can be pinned to it. Install method matters because it changes where the configuration, secrets and data live and which commands rebuild them. Where the source is on a Kubernetes-based install, the plan also notes that stateful components such as PostgreSQL and Redis are not run inside Kubernetes in the reference architectures, so the restore path must reach those services on their own hosts or managed services. Ask your team to confirm the exact version and edition in writing before any restore is scheduled.
Test restores run in an isolated environment inside the client's own infrastructure, built from the same package version as production and kept off the production network. The first test restores gitlab-secrets.json and gitlab.rb before any data, because an instance restored without its matching secrets file can lose access to encrypted database values. Only after that does the test restore the backup archive, then checks sign-in, repository clones, CI variables, container registry access and background job health. Each test records how long each step took, which steps needed manual intervention and which backup ID was used, so the run book reflects measured behavior rather than assumptions. Artifacts, LFS and uploads stored in object storage are restored from the storage provider's versioning or replication, not from the archive, so the test also confirms that path.
The run book is the deliverable that makes the test repeatable by people who were not in the room. It lists the version and edition pins, the install method commands, the order of secrets and configuration restoration, the verification checklist and the rollback point. It also states which upgrade stop applies if the target version must move forward after restore, since required upgrade stops mean a restored instance cannot simply jump to a later release. DeployOpen delivers the run book as part of a fixed-scope engagement with the scope and deliverables agreed in writing first, and retests it after each GitLab upgrade or change in install method. Ask any partner for the test environment design, the version pins they will use and the checklist they will hand over, and confirm the requirement for matching packages with your own change process before an incident forces the question.
How DeployOpen scopes, delivers and supports GitLab restore planning
DeployOpen plans, implements, documents and supports self-hosted open-source platforms inside your own infrastructure, including cloud accounts, data centers and air-gapped networks. For GitLab restores, that means matching the restore target to the backup's GitLab version and edition, planning the package versions, and proving the procedure works in a test environment before an incident or migration.
How we scope
- Inventory the running GitLab version, edition, install method and every node that holds state before choosing a restore target.
- Record which GitLab package versions, secrets files and configuration files must be retained alongside each backup archive.
- Agree the written scope in advance, including which restore scenarios are covered and which environments will be used for testing.
How we build
- Prepare a restore runbook that installs the matching package version and edition before any data is restored.
- Restore into a separate, isolated test instance, starting with gitlab-secrets.json and gitlab.rb, then the backup archive.
- Verify restored projects, users, CI/CD settings and runner registration against a checklist agreed in the scope.
How we hand over
- Deliver the restore runbook, version and edition matrix, and a record of each test restore with its results.
- Walk your operations and platform team through the procedure so they can repeat it without DeployOpen present.
- Document the upgrade stops your instance must pass through, so backup and restore plans stay aligned with later upgrades.
How we support
- Offer ongoing support, upgrades and continuous testing as a retainer, when your environment needs regular restore verification.
- Re-test restores after each GitLab upgrade, edition change or change to the secrets or storage configuration.
- Confirm with your team the support model, response expectations and retention periods before work starts, as these are set in the written agreement.

