Skip to content

Migrating from GitLab Package Registry

This is the field guide for moving from GitLab's Package Registry to OrbitalReg. It covers GitLab Self-Managed (Free, Premium, Ultimate) and GitLab.com (SaaS) on every supported package format. Container Registry is treated as a separate surface — see Container Registry migration below.

Coming from GitLab CI?

The OIDC integration is the strongest single reason GitLab teams move to OrbitalReg. CI_JOB_TOKEN exchange becomes a first-class trust policy on the OrbitalReg side — short-lived tokens, no PAT rotation, audit trail per pipeline. See OIDC trust translation for the migration mechanics.

What stays the same

For your developers, almost nothing visible changes:

  • Push and pull commands stay format-native (mvn deploy, npm publish, docker push, helm push, etc.)
  • Authentication mechanisms — Personal Access Tokens, Deploy Tokens, CI_JOB_TOKEN — all carry through with format-equivalent semantics
  • CI pipeline scripts only need their registry URL updated
  • Existing artifact identifiers (group:artifact:version, image tags) carry through unchanged
  • GitLab CI's OIDC ID-token (id_tokens.JOB_OIDC_TOKEN) translates 1:1 to OrbitalReg's OIDC trust policy

For your operations team, the big-picture shape changes:

  • One Go binary instead of GitLab's monolithic Rails application serving the registry surface
  • Registry workload decoupled from GitLab itself — no longer tied to GitLab's upgrade cadence or HA story
  • One Postgres database (OrbitalReg's own — not the GitLab schema)
  • One S3-compatible bucket instead of GitLab's object-storage configuration

What changes

ConceptGitLab Package RegistryOrbitalReg
Hosting modelEmbedded in GitLab (self-managed or .com)Standalone Go binary
DatabaseGitLab's PostgresOrbitalReg's own Postgres
Blob storageGitLab object storage (S3, Azure, GCS, NFS)S3-compatible (MinIO or native)
Format coverage~12 package formats + Container Registry40+ formats, all in one binary
Security scanningGitLab Vulnerability Reports (Ultimate)Trivy + Grype, all tiers
Container RegistrySeparate API surface, separate configSame Docker adapter, same UI
Pricing modelPer-user-per-month (Premium/Ultimate)Per-deployment annual flat-rate
Air-gapped operationPossible but tied to GitLab's offline modeDefault-on
OIDC for CINative (issued by GitLab itself)Trust policy on OrbitalReg side
Group / subgroup hierarchyNativeMapped to Project hierarchy

Pre-migration audit

The first step is always inventory. The orbital migrate plan command walks the GitLab Package Registry via the GitLab API v4, catalogues what it finds, and writes a plan file the apply step consumes.

bash
orbital migrate plan \
  --source gitlab \
  --endpoint https://gitlab.example.com \
  --token "$GITLAB_TOKEN" \
  --output migration-plan.json

The token needs read_api and read_repository scopes for inventory; write_repository if you also want to test re-push roundtrips during verification.

What gets discovered:

  • Groups and subgroups — GitLab's hierarchical group model is flattened into OrbitalReg projects with naming-convention-preserved identifiers (acme/backend/services becomes acme-backend-services by default; configurable)
  • Projects — each GitLab project that has any registry packages becomes an OrbitalReg project member
  • Packages — counted per format, sha256 sampled, version metadata preserved
  • Permissions — GitLab member roles (Guest / Reporter / Developer / Maintainer / Owner) translate to OrbitalReg roles
  • Deploy Tokens — flagged for translation to OrbitalReg scoped service-account tokens
  • Personal Access Tokens — not migrated automatically; users re-issue PATs against OrbitalReg post-cutover
  • Group-level dependency-proxy / package-proxy configurations — flagged as these become OrbitalReg's remote-mode repositories
  • Container Registry images — discovered via the Container Registry API; can be migrated in the same run or split into a separate phase

The output of plan is a JSON file. Read it before running apply. It is the contract between the audit and the migration.

Format coverage

OrbitalReg supports every format GitLab does, plus more. The format-by-format mapping:

GitLab formatOrbitalReg adapterNotes
MavenmavenSnapshot vs release semantics preserved. GitLab's Maven URL pattern (/api/v4/projects/:id/packages/maven) translates to OrbitalReg's standard Maven layout.
npmnpmScoped packages preserved. Project-scoped packages (GitLab convention) map to OrbitalReg's project-scoped repos directly.
DockerdockerManifests, layers, tags, multi-arch index.json. Note: GitLab's Container Registry is a separate API; this adapter covers both.
NuGetnugetNuGet v3 protocol. SemVer + prerelease tags preserved.
PyPIpypiwheels + sdists. Project-scoped packages flatten to flat namespaces under OrbitalReg.
ConanconanBoth Conan 1.x and 2.x supported.
ComposercomposerPHP package format. composer.json metadata preserved.
Helmhelmindex.yaml + .tgz tarballs + signed Chart.yaml provenance.
GenericgenericPath-based pass-through with sha256 verification.
Terraform ModuleterraformModule registry protocol.
DebianaptDistribution + component preserved.
RPMyumrepodata.xml + GPG signatures.
PubpubDart pub package format.
Container RegistrydockerTracked as a separate phase if you want — see About the GitLab Container Registry.

Permission model translation

GitLab's role-based access (Guest / Reporter / Developer / Maintainer / Owner) translates to OrbitalReg roles. The translator maps automatically where the semantics line up:

GitLabOrbitalReg
OwnerProject admin role
MaintainerProject admin role (with audit-log enabled)
DeveloperProject member with write-scoped token
ReporterProject viewer role with read-scoped token
GuestNo equivalent — Guests cannot push/pull packages anyway
Group-level permissionInherited project membership across all sub-projects
Project-level permissionDirect project membership

GitLab Deploy Tokens (project-scoped tokens with read_package_registry or write_package_registry scopes) translate to OrbitalReg service-account tokens with the equivalent format-and-action scopes.

OIDC trust translation

GitLab's CI_JOB_TOKEN and the longer-form id_tokens (Premium+) are the strongest single-feature reason to move to OrbitalReg with full OIDC trust. The translator generates an OIDC trust policy for each project that has CI publishing today.

GitLab CI usageOrbitalReg OIDC policy
CI_JOB_TOKEN for Maven push (default)Trust issuer https://gitlab.example.com, audience orbitalreg, subject pattern project_path:acme/backend:*
id_tokens.JOB_OIDC_TOKEN (Premium+)Same as above but uses the configured aud claim explicitly
Group-level CI variablesTranslate to OrbitalReg project-group settings

The translator emits the policy YAML; review the subject patterns carefully — they are the security boundary between projects in your GitLab hierarchy.

Webhook + automation translation

GitLab webhook events (filtered to package-related ones) map to OrbitalReg webhook events:

GitLab eventOrbitalReg event
Push to package registryartifact.uploaded
Package deletedartifact.deleted
Container Registry tag pushedartifact.uploaded (Docker format)
Container Registry tag deletedartifact.deleted (Docker format)

GitLab pipeline triggers on package events translate one-to-one if you keep GitLab CI as your build orchestrator (the recommended path). Migration does not require moving away from GitLab as a CI/CD platform — OrbitalReg replaces only the registry surface.

Pick your strategy

Use the matrix below — the orbital migrate plan step also recommends one based on what it sees.

Your situationRecommended strategy
Self-managed GitLab, registry under 500 GB, can take 2 h downtimeBig bang
Self-managed GitLab, production-critical, registry under 5 TBBlue-green parallel run
GitLab.com SaaS sourceLazy proxy (you don't control source lifecycle)
Huge registry (over 10 TB)Lazy proxy
Decommissioning GitLab entirely (move to GitHub Actions / Jenkins)Blue-green parallel run

Big bang cutover

Schedule a maintenance window. Run the migration end-to-end. Flip DNS.

text
Day -7   Announce maintenance window to all developer teams
Day -3   Dry-run on a copy of production (or a representative sample)
Day  0   Window opens
         00:00  Block writes to GitLab Package Registry
                (Admin Area → Settings → Packages → read-only mode)
         00:15  orbital migrate apply --plan migration-plan.json
         T+1h   apply complete — orbital migrate verify --sample 1000
         T+2h   Flip DNS: registry.example.com → OrbitalReg
         T+3h   Spot-check pulls from each format
         T+4h   Window closes — all clear
Day +30  GitLab Package Registry can stay read-only or be turned off

Total wall-clock time: 2-6 hours for registries up to 500 GB. GitLab's API is rate-limited per token, so plan parallel-token usage during inventory if your registry is dense (--workers 8 distributes load).

Blue-green parallel run

Run both registries simultaneously. Push to both. Pull from GitLab until verification passes, then flip DNS in a single change.

text
Day -14  Install OrbitalReg in parallel to GitLab
         Configure both as push targets in CI (dual-publish — see below)
Day -14  Run continuous import in the background
         Throttled to GitLab's per-token rate limit (~600 req/min default)
Day  -7  Cutover-readiness check — orbital migrate verify
         Sample sizes: 5,000 sha256 comparisons per format
Day  -3  Flip dev / staging DNS — soak for 72 h
Day   0  Flip production DNS in a single change
Day +14  Stop dual-publish — push only to OrbitalReg
Day +30  Decommission GitLab Package Registry surface
         (but keep GitLab itself for source/CI)

Dual-publish in GitLab CI is straightforward — the build job pushes to both $CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/maven and to https://registry.example.com/maven/... in the same step. Plan bandwidth for 2× write traffic during this window.

Lazy proxy cutover

For very large registries (over 10 TB) or when migrating from GitLab.com SaaS where you don't control the source's lifecycle, the lazy-proxy strategy avoids upfront full-import cost.

text
Day -14  Install OrbitalReg in front of GitLab as a remote-proxy
         Configure all repository entries as remote-mode pointing
         at the GitLab Package Registry endpoints
Day -14  Flip dev / staging DNS to OrbitalReg immediately
         All pulls go through OrbitalReg → cache fills naturally
Day -14  Soak — monitor cache-hit rate, error-rate, latency
Day  -7  Production DNS flip
         OrbitalReg now in front of all reads
         Writes still go to GitLab (will switch in next phase)
Day  +0  Switch CI to push to OrbitalReg directly
         New artifacts now land in OrbitalReg first
Day +14  When cache-hit rate exceeds 95%, switch repositories from
         remote-mode to local-mode
Day +30  Decommission GitLab Package Registry surface

For GitLab.com SaaS, the lazy-proxy path is strongly recommended: the GitLab.com API has aggressive rate-limits that make blue-green or big-bang bulk-export impractical at scale.

Cutover sequence (lazy proxy, detailed)

Here is the canonical lazy-proxy sequence with concrete commands.

Phase 1: Install OrbitalReg (Day -14)

bash
helm repo add orbitalreg https://charts.orbitalreg.com
helm install orbitalreg orbitalreg/orbitalreg \
  --namespace orbitalreg --create-namespace \
  --values your-values.yaml

kubectl wait --for=condition=ready pod -l app=orbitalreg-api \
  -n orbitalreg --timeout=300s

Phase 2: Configure remote-proxy mode + OIDC trust (Day -14)

bash
# Inventory
orbital migrate plan \
  --source gitlab \
  --endpoint https://gitlab.example.com \
  --token "$GITLAB_TOKEN" \
  --strategy lazy-proxy \
  --output migration-plan.json

# Apply — registers repositories + emits OIDC trust policies
orbital migrate apply --plan migration-plan.json

After this, OrbitalReg has every GitLab project's package endpoints configured as remote-proxy repositories, plus OIDC trust policies for every project that publishes via CI_JOB_TOKEN today. Pulls go through OrbitalReg, which fetches from GitLab on cache miss.

Phase 3: Soak on dev / staging (Day -14 to Day -7)

Switch dev and staging environments' CI variables to point at OrbitalReg. Monitor:

  • Cache-hit rate per repository (target: 60% within 7 days)
  • p99 pull latency vs GitLab baseline (acceptable: same or better — OrbitalReg's pull path has fewer hops than GitLab's Rails app serving the registry endpoint)
  • Error rate (acceptable: under 0.1%)
  • OIDC token-exchange success rate (target: 100% — failures here block CI builds)

Phase 4: Production DNS flip (Day -7)

bash
# Update DNS — registry.example.com → OrbitalReg ingress

Pulls now flow through OrbitalReg in production. Writes still target GitLab directly (CI configurations unchanged).

Phase 5: Switch CI to push to OrbitalReg (Day 0)

Update your .gitlab-ci.yml files to push to OrbitalReg. The OIDC trust translation step in Phase 2 already configured the auth side, so this is a one-line URL change in each pipeline:

yaml
# .gitlab-ci.yml example
publish-maven:
  image: maven:3-eclipse-temurin-17
  id_tokens:
    ORBITAL_OIDC_TOKEN:
      aud: orbitalreg
  script:
    - mvn deploy -DaltDeploymentRepository=orbital::default::https://registry.example.com/maven/${CI_PROJECT_PATH}

The ORBITAL_OIDC_TOKEN is exchanged for a short-lived OrbitalReg token via the trust policy emitted in Phase 2 — no PAT, no rotation, clean audit trail per pipeline.

Phase 6: Convert remote-mode to local-mode (Day +14)

Once cache-hit rates exceed 95%, switch repositories from remote-mode to local-mode.

bash
orbital migrate finalize --plan migration-plan.json

Phase 7: Decommission GitLab Package Registry (Day +30)

After 30 days of stable local-mode operation, you can disable the Package Registry feature in GitLab (Admin Area → Settings → Packages and Registries → Package Registry → disable). GitLab itself stays running for source code, MRs, and CI orchestration.

About the GitLab Container Registry

GitLab's Container Registry is a separate API surface from the Package Registry. It is migrated using the same OrbitalReg Docker adapter, but as a distinct phase to avoid mixing two API rate-limit budgets in the same window.

bash
# Container Registry as a separate planning pass
orbital migrate plan \
  --source gitlab-container \
  --endpoint https://gitlab.example.com \
  --token "$GITLAB_TOKEN" \
  --output container-migration-plan.json

orbital migrate apply --plan container-migration-plan.json

The Container Registry plan typically dominates registry-volume terms — Docker images are the largest individual artifacts. Many teams run the Container Registry migration on its own multi-week lazy-proxy schedule even when the Package Registry was big-banged.

Verification

Verification is what tells you it's safe to cut over.

bash
orbital migrate verify --sample 5000

What gets verified:

  1. Sha256 sample comparison — pulls a random sample from OrbitalReg, compares against the source.
  2. Metadata round-trip — for each format, verifies that format-specific metadata (Maven pom.xml, npm package.json, Docker manifests) round-trips correctly.
  3. Synthetic pull test — performs a real pull through the format-native client (mvn, npm, docker pull) on a sampled set.
  4. OIDC handshake test — exercises the trust policy with a synthetic GitLab CI ID-token; reports any subject-pattern divergence.
  5. Permission spot-check — re-runs each translated permission against a synthetic test user.

A clean run looks like this:

text
✓ 5000/5000 sha256 matches
✓ All metadata round-trips correctly (10 formats checked)
✓ Pull-test from random sample succeeded
✓ OIDC handshake: 47/47 trust policies authenticate correctly
✓ Permission spot-check: 89/89 roles match
→ Safe to flip DNS

Rollback

Same as for the other strategies: the lazy-proxy + blue-green paths make rollback trivial via DNS flip — GitLab's Package Registry was never touched destructively. For big-bang, restore from the maintenance-window snapshot.

FAQ

Are we forced to leave GitLab entirely?

No. OrbitalReg replaces only the registry surface. GitLab continues to host source code, MRs, issues, and CI/CD pipelines. The migration is registry-focused; nothing else moves.

What about GitLab CI integration?

OrbitalReg's OIDC trust integration is the strongest reason to move. GitLab CI's ID tokens (Premium+) authenticate to OrbitalReg via short- lived JWTs — no shared secrets, no PAT rotation, audit trail per pipeline. The migration translator emits trust policies automatically.

Will GitLab.com SaaS-hosted registries migrate cleanly?

Yes. Use the lazy-proxy strategy. The gitlab source adapter speaks the same GitLab API v4 against either self-managed or .com endpoints. Be aware of GitLab.com's per-user rate limits during the inventory pass.

Do we need to update Maven settings.xml?

Only the registry URL. The <server> block's authentication mechanism keeps working — bearer tokens, deploy tokens, or CI-injected tokens all translate.

What about GitLab's vulnerability scanning (Ultimate)?

OrbitalReg includes Trivy + Grype CVE scanning natively in every tier. GitLab's vulnerability scanning is per-pipeline; OrbitalReg's is per- artifact and on-demand. Most teams find them complementary rather than overlapping — keep GitLab's scanners running on the source side and add OrbitalReg's on the registry side.

How long does a full migration take?

Registry sizeBig bangBlue-greenLazy proxy
Under 500 GB2-6 h24 h elapsed14 days elapsed
1-5 TBnot recommended48-72 h elapsed21 days elapsed
5-10 TBnot recommended5-7 days elapsed30 days elapsed
Over 10 TBnot recommendednot recommended30-60 days elapsed
GitLab.com SaaS sourcenot recommendednot recommended30-60 days elapsed

What's the cost difference vs GitLab Premium / Ultimate?

GitLab licensing is per-user, per-month. A 200-developer team on Premium runs into six figures annually for the GitLab licence alone; Ultimate adds another tier. OrbitalReg is licensed per-deployment, annual flat-rate, with all security features included. Many teams keep their GitLab tier (for non-registry features like Premium's merge-request approvals) and simply add OrbitalReg on the registry side — the savings come from being able to scale developer headcount without a per-user registry tax.

Need a working session?

Email info@orbitalreg.com with subject "GitLab migration support" and we'll book a 60-minute working session. Customers in active migration get a dedicated channel for questions during the cutover window.

Released under the Apache-2.0 License.