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.