Jenkins to GitLab CI/CD migration starts with an inventory, not a rewrite
Moving builds from Jenkins to GitLab CI/CD on infrastructure you control is a staged translation of pipelines, plugin behavior, runner capacity and credentials, run in parallel until each pipeline is proven. The work starts by listing what Jenkins actually does today, not by rewriting Jenkinsfiles from memory. Engineering leaders should expect the inventory to take longer than the first conversions and should treat it as the basis for scope, sequencing and any quote they request.
The difficulty is that Jenkins pipelines often encode behavior nobody wrote down. Groovy in shared libraries may set environment variables, pick build agents by label, retry steps, or call external services. Plugins add behavior through controller configuration, such as credential bindings, notification hooks, or tool installers, and some of that state lives in the controller's file system rather than in version control. A pipeline that looks simple in its Jenkinsfile can depend on a plugin version or a global setting that the team has forgotten.
For each pipeline, record its triggers, the shared library functions it calls, every plugin step it uses, the agent labels it requires, the credentials it reads, and the artifacts and caches it expects. Then mark which behaviors have a direct GitLab CI/CD equivalent, which need a script or template, and which need a decision about whether to keep them at all. Ask the team who owns each shared library and whether any controller-level settings feed builds. Those answers, not the file count, determine how much effort the migration needs.
The GitLab side depends on runners, and runners must match the build environments the Jenkins agents provided. Compilers, SDKs, container tooling, network routes to internal registries and artifact stores, and access to build secrets all need to exist on the new runners before a converted job can pass. Record the operating systems, architectures and executor types each pipeline needs, and confirm with your platform team which ones can be provisioned in your own cloud accounts, data center or isolated network. Runner setup and hardening are covered in the Runner planning topic and are not repeated here.
This page covers pipeline migration only. Installing the GitLab platform, importing repositories and merge requests, setting up Runners and hardening the instance are separate topics and should be planned as their own workstreams. Use the inventory to decide which of those prerequisites must be finished before the first pipeline is moved, and confirm the GitLab version you will target against the maintenance policy and upgrade paths before scheduling the cutover.
Which Jenkins parts map to which GitLab CI/CD parts
Each Jenkins component has a GitLab counterpart, but the match is rarely one to one. Inventory every component on the controller and agents, then check how each one maps and what state or settings the mapping drops.
Stages and steps to pipeline jobs
Jenkinsfile stages and steps translate to .gitlab-ci.yml stages and jobs, and parallel branches become jobs in the same stage. The risk is state carried between steps. A Jenkins workspace persists across stages on the same agent, while each GitLab job starts from a fresh checkout, so files, environment changes and installed tools must be passed through artifacts, cache or the job image. Map each stage and check which steps depend on earlier output.
Shared libraries to includes and components
Jenkins shared libraries supply reusable Groovy functions and global variables loaded by version. In GitLab, the closest equivalents are include directives (local, project, remote or template files) and CI/CD components. The hidden risk is behavior that lived in library code, such as default image choices or notification calls, which must be rewritten and tested. Confirm which include and component forms your installed GitLab version supports.
Controller and agent nodes to runners
Jenkins agents and their labels map to GitLab Runners and runner tags, which route jobs to capacity. The risk is controller-level configuration that has no per-job equivalent, such as global tools, system settings and executor counts. Those settings move to the runner host or runner configuration, and the runner version should stay aligned with the GitLab version. Inventory every label and the tools each agent provides.
Credentials to CI/CD variables and file variables
Jenkins credentials stores, with their folder scoping, map to GitLab CI/CD variables and file-type variables defined at the project, group or instance level. The risks are scope and exposure: protected variables only reach protected branches or tags, masking has limits on which values can be hidden in logs, and secrets copied into .gitlab-ci.yml are visible to anyone with repository access. Document each credential's owner, scope and rotation process before cutover.
Plugin features to built-in features
Jenkins plugins for notifications, test reporting, deployment gates and approvals each need a GitLab built-in feature, a supported integration or a custom job. The risk is that some built-in CI/CD capabilities depend on the subscription tier. The GitLab pricing page lists advanced CI/CD in Premium, so confirm against the GitLab documentation for your installed version which CI/CD features your chosen tier includes before you commit to a replacement.
Artifacts and caches to job artifacts and cache keys
Jenkins archived artifacts and workspace caches map to GitLab job artifacts, which pass files between jobs and keep them for download, and to cache keys, which reuse dependencies across pipelines. The risk is that caches are a performance aid, not a guarantee, so builds that assume a warm cache can fail when it is missing. Set artifact expiry deliberately, since retained artifacts consume instance storage that someone must size and monitor.
Decisions to settle before translating any pipeline
This table compares the main choices a team makes before converting Jenkins jobs to GitLab CI/CD, with when each option fits and what it means for operations. Read each row as a decision to record before the first Jenkinsfile is touched. The main takeaway is that cutover style, shared pattern design and runner model shape the migration effort more than any single pipeline translation.
| Decision | Option | When it fits | Operational consequence |
|---|---|---|---|
| Cutover style | Big-bang cutover | Small job count with few shared dependencies and a short freeze window | All teams switch on one date, so rollback and support load concentrate in one period |
| Cutover style | Pipeline-by-pipeline migration | Many jobs, mixed owners or release trains that cannot pause | Two systems run in parallel, so secrets, webhooks and triggers must be tracked per job |
| Translation method | Hand translation | Few Jenkinsfiles or heavy custom Groovy logic | Slower to start, but each stage is reviewed as it is written |
| Translation method | Scripted first pass with review | Large set of similar Jenkinsfiles with common stages | Faster draft, but engineers must review every generated job for plugin-specific behavior |
| Shared patterns | Includes and CI/CD components | Several projects share build, test or deploy stages | One versioned definition to update, with consumers pinning versions and testing upgrades |
| Shared patterns | Copied per project | Projects differ widely or owners need full local control | Fast to start, but every fix must be applied to each copy and drift grows over time |
| Jenkins retirement | Keep selected pipelines on Jenkins | Legacy jobs depend on plugins or hardware that GitLab cannot reach yet | Two platforms stay in patch, access and backup scope for longer |
| Jenkins retirement | Retire Jenkins fully | Every pipeline has a verified GitLab replacement and an owner has signed off | One platform to run, but the decommission date must include secrets and audit log export |
| Runner ownership | Shared runners | Few projects with standard build images and no sensitive deployment access | Less to operate, but jobs from many projects compete for the same capacity |
| Runner ownership | Project or group runners on self-managed hardware | Deployments needing private network access or restricted secrets | Owners maintain hosts, Runner versions and capacity, so runner patching becomes a recurring task |
| Executor type | Shell executor | Jobs that must use tools already installed on a fixed host | Weakest isolation between jobs, so host state can leak between pipelines |
| Executor type | Docker executor | Jobs that need reproducible build images on a stable host | Image pulls and registry access become a dependency to monitor and cache |
| Executor type | Autoscaling executor | Bursty workloads that need elastic capacity on cloud or hypervisor infrastructure | Adds provisioning, instance images and scaling limits to operate, with cost tied to usage |
How Jenkinsfile constructs map to .gitlab-ci.yml and where plugins fall away
The core translation is structural. Jenkins stages become GitLab CI/CD stages, and parallel branches inside a stage become separate jobs that share that stage, so they run concurrently on available runners. A declarative Jenkinsfile maps almost line for line, because its pipeline, agent, stages and steps blocks have fixed meanings. A scripted Jenkinsfile is harder. Its node block and Groovy control flow can build the pipeline dynamically, so the team must decide which logic becomes static pipeline structure in .gitlab-ci.yml and which logic moves into a script the job calls. Cross-stage ordering that Jenkins expresses through sequential stages may need needs: in GitLab to allow jobs to start as soon as their dependencies finish. For example, in an illustrative pipeline, a parallel block with unit and integration test branches becomes two jobs in a test stage, each with its own script: section.
Conditionals are where most logic errors appear. A Jenkins when directive or an if check on env.BRANCH_NAME usually becomes a rules: clause on the job, using predefined variables such as $CI_COMMIT_BRANCH, $CI_PIPELINE_SOURCE and $CI_MERGE_REQUEST_IID. Pipeline-wide decisions, such as whether a pipeline runs at all for a given trigger, belong in workflow:rules. Groovy conditions that read files, parse output or call external systems do not translate directly to rule expressions. The usual approach is to compute the decision in an early job, pass it forward as a variable through artifacts or dotenv reports, and then gate later jobs on it. Each branch and trigger combination should be tested on a non-production project before cutover, because a rule that silently matches nothing will skip work without failing the pipeline.
Groovy helper functions need a new home. Repeated blocks of configuration can use YAML anchors or extends: inside one project. Logic shared across many repositories can move to a template file pulled in with include:, or to a CI/CD component that exposes named inputs and is referenced at a pinned version. Helper logic that is more than configuration, such as version parsing, deployment decisions or report generation, is better kept as a script in the repository, with its own tests and review. The team should assign an owner for every shared template, component and script, because these become the new Jenkins shared library. Without an owner, the migrated pipelines inherit the same drift that the shared library had in Jenkins.
Plugin features need an inventory, because each one has to be replaced, dropped or consciously accepted as lost. Build triggers from SCM polling, webhooks and cron usually become GitLab push or merge request pipelines, pipeline schedules and API triggers. JUnit test publishing maps to artifacts:reports:junit, and archived files map to artifacts:paths with an expiry. Email and chat notifications map to GitLab integrations where they exist, or to a script that the team owns. Some behavior has no one-to-one equivalent, including interactive input steps with complex parameter forms, custom Jenkins views, certain plugin-specific checkout or reporting behaviors and post-build chaining. Each replaced plugin needs a named owner who confirms, on the team's GitLab version and tier, that the replacement works as expected. Confirm the tier as well, because some features the team relies on may sit outside the edition it has purchased.
Build sequence for moving pipelines from Jenkins to GitLab CI/CD
This sequence moves build and deploy pipelines from Jenkins to GitLab CI/CD one pipeline at a time, so each cutover is proven against the Jenkins output before the next one moves. The result is a documented inventory, a verified pilot, and a Jenkins controller that is switched off and archived only after every pipeline has a passing GitLab replacement.
Inventory every Jenkins job and dependency
Your team, with DeployOpen if engaged, lists every Jenkins job, pipeline, controller plugin, shared library, credential and build agent, and records which jobs trigger which others. The inventory also notes which jobs deploy to which environments and which depend on specific tools installed on agents. It is done when the list is reviewed by the people who own each job, and every item is marked as migrate, replace with a built-in feature, retire, or keep outside CI. Unlisted dependencies are the most common source of later surprises, so the check is a signed-off inventory with no unassigned items.
Choose a low-risk pilot pipeline
Select one pipeline that builds and tests regularly, has few external dependencies, does not deploy to production, and has an owner who will review its results. Avoid pipelines that rely on shared libraries you have not yet mapped or on credentials that are hard to rotate. The pilot is closed when the owner and the platform lead have agreed on it in writing, along with the success criteria for the parallel run. This choice sets the pattern for later waves, so it should be representative of common build steps even if it is small.
Stand up GitLab and a matching Runner pool
Install the self-managed GitLab instance in your environment and register Runners that reproduce the pilot's build environment, including operating system, language toolchains, container tooling and network access to internal artifact stores. Choose executors that fit the workload and confirm that Runner and GitLab versions are aligned, as the GitLab Runner documentation advises. Check the setup by running a trivial job on each Runner tag and confirming that it reaches the expected image, tools and network endpoints. The step closes when a test job produces the same tool versions that the Jenkins agent reports.
Translate and review the pilot pipeline
Rewrite the pilot Jenkinsfile as a .gitlab-ci.yml file, replacing each plugin step with a built-in GitLab feature, a template, or a script you maintain. Keep stages, caching, artifacts and approvals explicit so the reviewer can compare them with the original. The pilot owners review the translated file in a merge request and confirm the behavior of each job, including conditions and failure handling. The step is complete when the pilot branch shows a green pipeline and the owners have approved the merge request, recorded as a documented sign-off.
Move pilot credentials into scoped GitLab variables
Recreate each credential the pilot uses as a GitLab CI/CD variable or as an entry in an external secrets store, with protected and masked settings where appropriate and scopes limited to the branches or environments that need them. Retire the old Jenkins credential references once the GitLab copies work, and rotate any secret that was exposed to a shared agent or plugin. Confirm that the pilot job reads each value without printing it in logs. The check is a list of every pilot credential with its scope, owner and rotation status, reviewed by the security owner.
Run the pilot in parallel and compare outputs
Keep the Jenkins pipeline running alongside the GitLab pipeline for the same commits over an agreed period, without letting both deploy to the same target. Compare build artifacts, test counts, image digests, logs for warnings, and timing against the success criteria set earlier. Investigate every difference, because differences often reveal missing environment variables or tool versions. The step closes when the outputs match on the criteria the owners agreed and the differences that remain are documented and accepted.
Migrate the remaining pipelines in waves
Group the remaining pipelines by shared dependencies and risk, then move them in waves, applying the same translation, credential and parallel-run checks to each group. Shared libraries are usually converted into GitLab templates or components before the pipelines that use them. Keep a tracking list that shows each pipeline's status, owner and remaining Jenkins dependencies. Each wave closes when its pipelines pass the parallel-run comparison and their owners sign off, so the final wave is not the first real test of the platform.
Disable Jenkins triggers and archive its configuration
Once every pipeline has a verified GitLab replacement, disable the Jenkins triggers, webhooks and scheduled builds, then keep the controller read-only for an agreed retention period. Export job definitions, plugin lists, credential references without secret values, and the shared library source to a controlled archive, and record where the archive is stored. Confirm that no repository still points at a Jenkins webhook and that no scheduled job is still active. The sequence closes with a written decommissioning record that lists the archive location and the people authorized to restore it.
Runner capacity during the transition by deployment model
A single-node or small self-managed GitLab often shares a few servers with build work, so the first decision is whether Jenkins agents and GitLab Runners will run on the same machines. Plan capacity for both systems together, because a busy Jenkins controller or agent can starve a Runner of CPU, memory or disk when jobs from both systems overlap.
- Separate the Runner host from the GitLab data host where you can, so build jobs never write to the disks that hold repositories and databases.
- Start with the shell or Docker executor when existing Jenkins agents already run on fixed machines. Confirm in the GitLab Runner documentation that these executors fit your operating systems and workloads.
- Tag each Runner narrowly so migrated pipelines land only on hosts you have documented.
- Reuse Jenkins agents in place by registering them as Runners after you record their installed tools and credentials, then retire them one group at a time.
- Keep Runner and GitLab on the same major and minor version, and schedule Runner upgrades in the same window as GitLab upgrades.
Before registering any Runner on a host, confirm which Jenkins agents are unmanaged, meaning no team owns their image or patch cycle, and decide whether they are retired or brought under the same change process.
When GitLab runs across several nodes, the usual pattern is a Runner fleet that is separate from the GitLab application nodes and owned by the platform team. During the transition, Jenkins agents and the new Runner fleet often coexist, so each fleet needs a named owner, a capacity target and a clear list of the projects it serves.
- Create one Runner fleet per trust zone or workload class, such as production deployments, general builds and privileged jobs, so a failure or compromise in one fleet stays contained.
- Pin the Runner version to the GitLab minor version and document the pin in the same change record as the GitLab upgrade.
- Move projects by group and keep a Jenkins pool serving the groups that have not moved yet, so each cutover changes one set of pipelines.
- Set concurrency limits per fleet based on the build hosts you own, and confirm that the sum across Jenkins and GitLab does not exceed what those hosts can run.
- Retire Jenkins agents only after no Jenkins job is scheduled to them for an agreed period and their last build logs are archived.
Read the GitLab reference architecture guidance for your user count before sizing the fleet, since the instance size and the Runner fleet size are planned separately but must fit the same network and identity design.
GitLab Runner supports autoscaling executors that create build machines on cloud or hypervisor capacity when jobs arrive and remove them when the queue empties. This model changes the transition math: capacity is elastic, but quotas, images and cost are fixed decisions that must be made before the first migrated pipeline runs.
- Keep the Jenkins static pool separate from the autoscaled pool so that Jenkins scaling events do not consume the quota the Runners need, and the reverse.
- Set the maximum machine count from your quota, not from the number of Jenkins agents you retire, and confirm the limit with the cloud or hypervisor team.
- Build and version the machine images that autoscaled Runners use, and keep those images on the same Runner version as the GitLab instance.
- Track idle capacity cost during overlap, since two schedulers can keep machines warm at the same time.
- Drain Jenkins agents by disabling new job assignment, waiting for running builds to finish and then removing the agent from the controller.
Before enabling autoscaling for migrated jobs, confirm in the GitLab Runner documentation which autoscaling drivers match your cloud or hypervisor platform and which executor each driver requires.
On isolated or air-gapped networks, runner capacity depends on what you can transfer across the boundary. Runner binaries, helper images, base images and any package sources used in jobs must come from an internal mirror or an offline transfer, which makes version alignment slower to change than on connected networks. GitLab documents offline environments separately, so plan against that guidance together with the Runner documentation.
- Inventory every image and package that migrated jobs pull, including those Jenkins agents currently fetch during builds, and mirror them before the cutover.
- Schedule Runner and GitLab updates as one offline bundle so the Runner never moves ahead of or behind the instance version by accident.
- Choose executors that run without public registries, and confirm that each one can use your internal image repository.
- Keep Jenkins agents isolated from the Runner network during overlap, so credentials and build artifacts do not cross between the two systems.
- Retire Jenkins agents on a fixed calendar with a rollback plan that includes the offline images for the previous Runner version.
Confirm with your security and network teams which hosts are permitted to hold Runner registration tokens, because that decision determines where each fleet can be placed.
What drives the effort of a Jenkins to GitLab CI/CD migration
This table lists the factors that most change how much work a Jenkins to GitLab CI/CD migration takes, why each one matters and what to do to keep it contained. Read each row as a question to answer about your own Jenkins estate before requesting a quote, because the same pipeline count can mean very different work depending on shared libraries, plugins and compliance evidence. The main takeaway is that inventory and rationalization before translation usually matter more than the translation itself.
| Effort driver | Why it matters | How to keep it down |
|---|---|---|
| Number of pipelines and branches | Each Jenkinsfile, multibranch job and long-lived branch needs a translated .gitlab-ci.yml, a test run and a reviewer. Stale jobs multiply the work without adding value. Who pays: internal staff or a partner, one-time. | Inventory all jobs, archive unused pipelines and branches, and migrate only active projects in the first wave. |
| Shared-library and Groovy logic | Jenkins shared libraries and scripted pipelines often hold custom control flow that has no direct YAML equivalent and must be redesigned, not copied. Who pays: usually the partner or senior engineers, one-time. | Catalog every library function, convert repeated logic into GitLab CI/CD templates or components, and cap custom scripting in pipeline code. |
| Number and type of installed plugins | Each plugin is a feature the pipelines may depend on. Some map to built-in GitLab functions, others need an external tool or a custom job. Who pays: internal staff or a partner, one-time. | List plugins actually referenced by jobs, map each to a built-in feature or chosen tool, and drop plugins that no pipeline uses. |
| Number and scope of credentials | Jenkins credentials must be recreated as GitLab CI/CD variables, protected or masked settings or external secret references, with scopes checked for each project and environment. Who pays: internal security staff with a partner, one-time, plus ongoing rotation. | Export a credential inventory without values, assign each secret a scope and owner, and prefer short-lived or externally managed secrets. |
| Build environment variety across agents | Jenkins agents with different operating systems, tool versions and hand-installed software must each be reproduced as runner tags, container images or executors. Who pays: internal platform staff, one-time build plus recurring image upkeep. | Standardize on a small set of container images and runner tags, and document any agent that still depends on local host state. |
| Test and artifact volume | Large test suites, long build times and big artifact sets affect runner capacity, cache design and storage retention settings, and they lengthen validation runs. Who pays: internal platform staff, recurring storage and compute. | Measure current build durations and artifact sizes, set retention rules up front, and parallelize or trim slow stages before cutover. |
| Number of teams that must review translated pipelines | Each owning team checks that its jobs still build, deploy and gate releases the same way, so review time scales with team count and pipeline ownership clarity. Who pays: internal teams, one-time. | Assign a named reviewer per pipeline group, agree acceptance tests for each, and schedule reviews in batches rather than one at a time. |
| Integrations with external systems | Deployment targets, artifact registries, ticketing, chat and approval tools each need connection details, authentication and tested pipeline steps. Who pays: internal staff or a partner, one-time plus recurring credential maintenance. | List every external call made from Jenkins, confirm the GitLab method for each (native integration, API call or script), and test them in a staging project. |
| Compliance evidence requirements for pipeline changes | Assessors may expect records of who changed pipeline definitions, how changes were reviewed and how release gates were enforced. Translated pipelines must produce comparable evidence. Who pays: internal compliance and engineering staff, recurring. Confirm the exact evidence with your auditor. | Agree the evidence list before translation, enable protected branches and required approvals for pipeline files, and keep review records linked to merge requests. |
Moving secrets and access without copying Jenkins credentials
Migrating from Jenkins is a good point to decide which credentials still deserve to exist. The cards below cover inventory, rotation, scope mapping, external secret sources and runner isolation, which together keep old Jenkins secrets from quietly following pipelines into GitLab CI/CD.
Inventory Jenkins credentials before migrating
List every credential in the Jenkins credential store, folder and job scope, and any credential referenced by a Jenkinsfile, shared library or plugin configuration. Record which pipelines use each one and when it was last used. Credentials that no pipeline references should be retired in Jenkins rather than copied into GitLab, so the migration starts from a smaller and better understood set.
Rotate credentials exposed to Jenkins
Treat as exposed any credential that was available on Jenkins agents shared between projects, written to build logs, or stored in workspaces that were not cleaned between builds. Rotate these before cutover, and confirm with the owning service whether the old value can still authenticate. Rotation is a one-time task for the migration, but the steps should be documented so the same check can be repeated later.
Map Jenkins scopes to GitLab variables
Translate each Jenkins credential scope into the matching GitLab CI/CD variable scope, using environment scopes, protected variables and masked variables where the value allows it. Check that protected variables are only exposed to protected branches and tags, and that masking rules fit the value format. Confirm the exact behavior of each setting against the current GitLab documentation for your version before relying on it.
Prefer externally sourced secrets
Where the organization already runs a secrets vault or cloud secrets manager, have GitLab jobs retrieve short-lived credentials from it at runtime instead of storing long-lived values in GitLab variables. This reduces the number of copies that need rotation and makes revocation a vault action. Confirm which vault products and authentication methods your runners can reach, and who owns access policies on each side.
Separate untrusted and production runners
Run jobs that build untrusted branches, forks or merge requests on runners that cannot reach production credentials or deployment targets. Runners that deploy should accept jobs only from protected branches, and should run on dedicated infrastructure with their own tags. Review the GitLab hardening documentation for instance-wide CI/CD and runner settings, and rely on the sibling GitLab security hardening topic for the wider instance setup. That guidance is a work in progress that GitLab describes as a gradual rollout, so check which settings your version supports.
How to prove each GitLab pipeline matches its Jenkins original
The only defensible proof that a migrated pipeline matches its Jenkins original is a side-by-side run on the same commit, with the outputs compared rather than assumed. Pick a representative set of pipelines, including at least one that builds, one that runs a full test suite and one that deploys, then trigger the Jenkins job and the new .gitlab-ci.yml pipeline against the identical commit SHA. Record the produced artifacts and compare their checksums (SHA-256 is a sensible choice). If the checksums differ, find out why before going further: timestamps embedded in archives, non-deterministic build steps and differing base images are the usual causes, and each one needs a documented explanation or a fix. Test parity is a separate check. Compare the number of tests executed, passed, skipped and failed in each run, and compare the JUnit or equivalent reports, not just the pipeline color. A GitLab pipeline can turn green while silently skipping a stage that Jenkins ran, because a rule or a needs: dependency was written differently. Also compare which environment variables each job sees and which deployment target it resolves to. Run this first in a non-production environment with a non-production copy of the secrets, and confirm that no job writes to a production host, registry or cloud account during parity testing. Failure paths deserve the same scrutiny as the success path. Deliberately break the pipeline in controlled ways and confirm the outcome. A failing unit test should stop the pipeline before any deploy job starts. A missing or misnamed CI/CD variable should fail the job with a clear error and never fall back to an empty value that deploys anyway. A runner that goes offline or is removed mid-run should leave the job pending or failed, not succeeded. For each case, record the expected behavior, the observed behavior and the deployment target state afterward. Ask the owner of each pipeline to review these results, because they know which failures matter most in their environment. The rollback path has to be designed before cutover, not improvised after an incident. Keep the Jenkins job able to build and deploy until the pipeline owner signs off in writing, and do not decommission the controller or its credentials while that sign-off is pending. Define the triggers in advance. Typical triggers include a parity mismatch in artifacts or test counts that is not explained within an agreed review window, a failed production deployment that cannot be corrected quickly in GitLab, or runner capacity that cannot keep up with queued jobs. Agree who can make the call to return to Jenkins and how the team confirms that Jenkins is still healthy. Before cutover, confirm three things with your team: the parity evidence is stored where auditors and owners can read it, the rollback owner and triggers are written down, and the Jenkins job remains runnable with its current credentials. The exact review window, approval chain and sign-off format depend on your change management process, so confirm them with your own governance owners rather than adopting a standard template.
What to monitor, back up and document after cutover
Once pipelines run on GitLab CI/CD, the risk moves from writing jobs to operating the platform beneath them. The cards below cover what to watch, which versions must stay in step, what GitLab itself must protect, and how ownership and the Jenkins retirement date get recorded.
Runner queue time and failure rates
Track how long jobs wait for a runner and how often jobs fail, broken down by runner pool and by pipeline. Queue time shows whether runner capacity matches the load the migrated pipelines create, and failure rates separate translation errors from infrastructure faults. Record Jenkins baselines before cutover so the comparison is fair. Review both measures weekly during the first months, then set alert thresholds your team agrees on.
Runner and GitLab version alignment
GitLab Runner distributes separately from the GitLab instance, and the Runner documentation advises keeping its major and minor versions aligned with GitLab. Build an inventory of every runner host, container image and autoscaling template with its version. Check that inventory after each GitLab upgrade, because a runner that falls behind can fail jobs in ways that look like pipeline bugs.
Upgrade stops and release cadence
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. GitLab also ships a minor release on the third Thursday of each month. Pipelines that rely on keywords or features added in newer releases tie the platform to a faster upgrade path. Plan the stop sequence and a test window in advance. The upgrades topic covers the procedure in depth.
Instance backups and the secrets file
Pipeline definitions in Git do not capture the GitLab instance itself, including its database, repositories, uploads and the secrets file that encrypts stored tokens and variables. Back up the instance with the gitlab-backup tool and store the secrets and configuration files separately, on a path with its own access controls. Confirm that a restore has been tested on a separate host. The backup and restore topic covers the procedure.
Pipeline repository and shared template review
Shared CI/CD templates and components become a single point of change for many projects. Keep them in a dedicated repository with merge request approval, versioned tags and a named maintainer group. Review changes to templates the same way you review application code, and run a pipeline against a sample project before publishing. Projects that include a template by a moving reference will pick up unreviewed changes, so pin references to tags.
Ownership records and Jenkins decommission date
Record a named owner for each pipeline, each runner pool and each runner host, along with the team that approves changes to them. Then set a date to decommission Jenkins controllers and agents, after the parallel run has confirmed that every migrated pipeline passes. Keep a read-only archive of the Jenkins configuration and job history for the period your audit or release records require. Review the ownership register at each upgrade stop.
Questions teams ask before moving from Jenkins to GitLab CI/CD
How much does a Jenkins to GitLab CI/CD migration cost?
The cost follows the written scope. DeployOpen does not publish a price list, and a quote is based on what is agreed in writing before work starts. Most migration work is one-time: inventorying Jenkins jobs, translating Jenkinsfiles to .gitlab-ci.yml, rebuilding credentials and deploy steps, setting up runners and testing each pipeline.
The main drivers are the number of pipelines, how many plugins and shared libraries they depend on, the number of deploy targets, and how much pipeline logic is undocumented. Recurring costs are separate. GitLab licensing depends on the tier you choose. According to the GitLab pricing page, Free is listed at 0 US dollars, Premium at 29 US dollars per user per month billed annually, and Ultimate is custom priced. Runner compute and ongoing maintenance also recur. Ask for any quote to show one-time migration work, runner infrastructure and licensing as separate lines.
How long does moving Jenkins pipelines to GitLab take?
Duration depends mainly on pipeline count and plugin use. A small set of straightforward pipelines moves much faster than a large estate with custom plugins, shared libraries and environment-specific logic. Each pipeline needs translation, a test run, and a review of what it deploys and where.
Plugin use is often the biggest variable. Some Jenkins plugin behavior maps to GitLab CI/CD features that are built in, and some needs a different design, such as a template, a component, a script or an external tool. Each plugin must be checked against the features your GitLab tier includes. Ask the implementation partner to list pipelines, plugins, shared libraries, credentials and deploy targets during scoping, since these inventory results determine the schedule in the written scope.
What does our internal team need to provide during a migration?
Three roles are needed from your side. Pipeline owners explain what each pipeline builds, tests and deploys, and they approve the translated version. Without them, undocumented behavior is discovered late. A runner host owner provides and maintains the machines or cloud capacity where GitLab Runners execute jobs, and decides how they are patched and scaled. A security reviewer checks how secrets, protected variables, deploy credentials and runner isolation are handled before pipelines go live.
Time from these people is a schedule driver. Ask the partner to name each role, the expected review points, and who signs off each pipeline cutover in the written scope.
Can our own team migrate Jenkins pipelines without a partner?
Yes, a capable internal team can migrate pipelines alone, and the decision depends on capacity and experience. Your team needs people who understand the existing Jenkins jobs, can write GitLab CI/CD configuration, can build and operate runners, and can test deployments safely. The work is more difficult when pipelines are poorly documented or the team has no time to run the old and new systems side by side.
A partner adds value mainly through scoping, translation patterns and verification. Decide by comparing the inventory of your pipelines against your team's current workload and skills. DeployOpen plans, implements and documents this kind of migration inside your own infrastructure and scopes the work in writing before starting, so you can compare that scope with an internal plan.
Does our GitLab tier limit which CI/CD features we can use?
Yes, the tier determines some CI/CD and security features. According to the GitLab pricing page, Premium includes advanced CI/CD and priority support, while Ultimate adds application security testing, software supply chain security, vulnerability management and compliance features. Free covers core CI/CD functions, so pipelines that depend on advanced features need a paid tier.
Check this before translating pipelines. Map each Jenkins behavior you rely on to a GitLab feature, then confirm that feature is available in the tier you plan to buy. Feature availability changes between releases, so confirm the current tier matrix with GitLab and record the result in your scope.
Can Jenkins keep running while we move pipelines to GitLab?
Yes, most teams run both systems during the transition. Pipelines are usually moved in groups, one project or team at a time. Each moved project is tested in GitLab while its Jenkins job stays available until the cutover is approved. This lets you fall back to Jenkins if a translated pipeline fails.
Watch for shared resources. Jenkins and GitLab should not both deploy to the same environment without a clear rule, and credentials used by both systems need a plan so that rotation or revocation does not break the other. Source webhooks, artifact paths and scheduled jobs also need an owner so that nothing runs twice or stops silently. Record the cutover order, the fallback path and the decommissioning date for each Jenkins job in the written scope.
Where should GitLab Runners run during a Jenkins migration?
Runners should run on infrastructure you control, sized to the moved pipelines. GitLab Runner is distributed under the MIT license and supports shell, Docker and autoscaling executors across clouds and hypervisors. Choose the executor based on how your current Jenkins agents build and isolate jobs, and plan separate runners for jobs that need different levels of trust, such as production deployments.
Keep versions aligned. GitLab's documentation advises keeping Runner major and minor versions aligned with GitLab, so the runner host owner needs an upgrade plan that follows each GitLab release. Confirm capacity by testing representative pipelines before the first production cutover, since runner sizing is one of the less visible effort drivers.
How DeployOpen scopes, builds and hands over a Jenkins to GitLab CI/CD migration
DeployOpen plans, builds and hands over Jenkins to GitLab CI/CD migrations inside your own infrastructure, on a self-managed GitLab instance you control. We start from a written inventory of your pipelines, plugins, runners and secrets, then translate and test each pipeline in a staged way while Jenkins keeps running until cutover is agreed.
How we scope
- The written scope lists every Jenkins job, pipeline and shared library to be translated, retired or kept in place.
- Plugin usage is mapped to GitLab CI/CD built-in features, templates or custom jobs, with each substitution recorded for review.
- Runner capacity, executor types and network access to build targets are agreed in writing before any pipeline is moved.
- Engagements are fixed-scope, so deliverables and timelines are agreed in writing before work starts.
How we build
- Jenkinsfiles are translated into .gitlab-ci.yml, with stages, artifacts and caching reproduced and checked against the original job output.
- Credentials move into GitLab CI/CD variables or an external secrets store, with protected and masked settings applied where appropriate.
- Runners are installed and configured for the agreed executors, and test pipelines run in parallel with Jenkins until results match.
- Cutover runs in stages by project or team, with a documented rollback path back to the Jenkins job for each pipeline moved.
How we hand over
- You receive the translated pipelines, a mapping document from each Jenkins plugin to its GitLab equivalent, and the runner configuration.
- Runbooks cover adding projects, rotating runner tokens, handling failed jobs and retiring Jenkins agents and credentials safely.
- Knowledge transfer sessions walk your engineers through the pipeline layout so they can change jobs without outside help.
- Acceptance criteria from the written scope are reviewed with your team, and open items are logged with owners and dates.
How we support
- Ongoing support, GitLab upgrades and continuous testing are available as retainers after handover.
- Support can cover runner version alignment with GitLab, since the documentation advises keeping them matched.
- Retainer scope, response expectations and upgrade stops are agreed in writing with your team.
- Confirm with your GitLab tier which CI/CD features you need, since advanced CI/CD features depend on the edition you choose.

