intermediatecigithub-actionsgitlab-cimigration

GitHub Actions → GitLab CI Migration: The Survival Guide

Porting a 12-repo pipeline estate from Actions to GitLab CI without a production incident.

By Mohamed SalahApr 23, 2026

GitHub Actions → GitLab CI Migration: The Survival Guide

A client consolidated to GitLab and I had a month to port 12 repos of Actions pipelines to .gitlab-ci.yml. Here's the pattern that worked.

1. Do a shadow run first

Don't delete the Action. Add a GitLab runner that mirrors the repo and runs the new pipeline in parallel. Both green for a week → switch over.

2. Translate, don't rewrite

| GitHub Actions | GitLab CI | |---|---| | on: push | default | | jobs.<name>.needs | needs (same name!) | | matrix | parallel:matrix | | secrets.GITHUB_TOKEN | $CI_JOB_TOKEN | | Reusable workflows (uses:) | include: project |

The mental model is the same; the syntax rewrites are mechanical.

3. The trap: cache semantics

Actions caches are keyed by a hash you compute; GitLab CI caches are keyed per-branch by default. If your build relies on "global" npm cache, switch to cache:key: ${CI_COMMIT_REF_SLUG}-build and lose some hit rate in exchange for correctness.

4. The other trap: OIDC

Actions' OIDC-to-AWS story is first-class. GitLab supports it too via id_tokens, but the trust policy shape is different. Update the IAM trust policy before you flip the default branch.