Migrate from TeamCity to GitLab CI/CD

Moving TeamCity build configurations, agents and parameters onto self-managed GitLab CI/CD is mostly a planning and rewrite job, and the plan has to start before the first pipeline is ported.

On this page

How much work is a TeamCity to GitLab CI/CD migration

The pipeline rewrite is the visible part of a TeamCity to GitLab CI/CD migration, but it is rarely the part that sets the schedule. A team with TeamCity build configurations, agents and shared templates will rewrite each configuration as jobs in .gitlab-ci.yml, map agents to GitLab Runners and move parameters into CI/CD variables. The mapping is well documented, so a single build chain can often be rebuilt quickly. Effort grows with the number of configurations, how many of them depend on shared logic, and how many distinct build environments the agents provide. Before estimating, ask your team to inventory every build configuration, template, agent pool and deployment target, because the count of those objects drives most of the work.

The schedule is set by what sits around the pipelines. GitLab's migration guidance asks teams to plan first for plugins, agent software, shared libraries, credentials and cross-project access. Each TeamCity plugin needs a replacement, a built-in feature or a retirement decision. Agent images carry toolchains, certificates and licenses that must be reproduced on runners. Shared build libraries and templates need a home in GitLab, such as includes or project templates. Credentials stored in TeamCity must be re-issued as masked, protected CI/CD variables or pulled from a secrets manager, and every project that reads another project's artifacts or builds needs its access rethought. Confirm each of these with your own administrators and owners of the shared pieces before committing to dates.

The source Git repositories can move separately from the CI rewrite, and it is usually safer to do so. Moving repositories first lets teams run GitLab pipelines against code that already lives in GitLab while TeamCity still builds other projects, which shortens the period when two systems must stay in step. It also lets you test runners and variables on low-risk projects early. The repository move has its own effort, covering import method, user mapping and history, and it should be scoped in the same written plan so that the two workstreams share one cutover calendar.

Which TeamCity concepts map to GitLab and which need redesign

This table compares common TeamCity concepts with their closest GitLab CI/CD equivalents and marks each as direct, partial or needs redesign. Use it to size the rewrite before any pipeline code is written, and confirm each row against the GitLab TeamCity migration guide.

TeamCity conceptGitLab equivalentMapping and what to plan
Build configurationJob in .gitlab-ci.ymlDirect. Each build configuration becomes a job, but steps, settings and dependencies must be rewritten by hand in YAML.
AgentRunnerDirect at the concept level. Agent pools, agent requirements and OS images need new runner registration, tags and executor choices.
ParametersCI/CD variablesPartial. Masking, protected scope and environment-level values must be re-created, and parameter references need new syntax.
Artifactsartifacts keywordDirect for most cases. Confirm retention, paths and cross-job passing against the migration guide.
Build chains and snapshot dependenciesNeeds redesignNeeds redesign. Usually rebuilt with needs, dependencies, multi-project pipelines or child pipelines, so the graph should be drawn first.
Triggers (VCS, schedule, finish build)Rules, schedules and pipeline triggersPartial. Branch and path logic moves to rules and schedules are set separately, but trigger chains across projects need design.
VCS rootsProject repository configurationPartial. Repository access moves to GitLab project settings, deploy keys or tokens, and branch selection moves into rules.
Build templatesIncludes, extends or CI/CD componentsPartial. Shared templates map to include and extends patterns, but parameter contracts usually need redesign.
Plugins and custom build featuresRunner features, scripts or external integrationsNeeds redesign. Each plugin must be replaced, retired or reimplemented, so inventory them before any rewrite starts.
Custom build feature logic and scriptsJob scripts or custom imagesNeeds redesign. Logic tied to TeamCity server APIs must be rewritten, and secrets should move to the GitLab secrets model.

Which documented paths move repositories and history

The TeamCity migration guide covers pipeline concepts, not repository import. It maps build configurations to jobs in .gitlab-ci.yml, agents to runners, parameters to CI/CD variables and artifacts to the artifacts keyword. It does not move source code, so repositories and their history need a separate path. TeamCity is not a source that GitLab's importer reads from, so you cannot point the GitLab import feature at a TeamCity server and expect builds to arrive. Source code moves through GitLab's documented Git options, such as importing Git repositories by URL or by manifest, and every pipeline definition is rewritten by hand or with your own tooling.

Before you choose an import path, confirm current importer coverage in the GitLab import documentation, because the list of supported sources changes between releases. Check where each repository is hosted, since the answer depends on whether its origin is a Git host that GitLab imports from directly or a plain Git remote. Repositories that live in a version control system other than Git need a conversion step first, and that step is covered in the sibling migration topics. Record, for each repository, the source host, the default branch, whether it uses Git LFS and whether its history contains large binaries. These facts decide whether a URL import is enough or whether you need a mirror push.

Keep the repository move and the pipeline rewrite in separate work streams. A repository can be live in GitLab while its build still runs in TeamCity, which lets you validate history and access first and then switch CI. Ask your partner or internal team to show, for a test project, the exact import method, the user and permission mapping result, and a clone from the new location that matches the source commit. Confirm with the vendor how the import handles tags, protected branches and merge request history, since TeamCity does not hold those objects in the way GitLab does. Write down what does not transfer so that the cutover checklist reflects reality rather than assumptions.

Documented import and migration options to evaluate

A TeamCity move into GitLab touches four things: source code, build logic, the runners that replace TeamCity agents, and the instance that hosts it all. The options below are the documented starting points for each, and each one needs a check against your own TeamCity inventory before the team commits to a plan.

Repository import by URL or manifest

GitLab can import Git repositories by URL or from a manifest file, which suits the source code side of a TeamCity move when your VCS roots already point at Git. Confirm that every VCS root in TeamCity maps to a Git repository you can reach from the new instance, and list any roots that use Perforce, TFVC or another system that needs conversion first. Check branch and tag coverage, since build configurations often depend on specific branches. Credentials for each source must be planned before the import runs.

Source platform import documentation

The GitLab import documentation covers several source platforms and file-based options, which matters when TeamCity sits next to a hosted Git service. Use it to confirm which importer applies to each repository and which items, such as issues or merge requests, do not carry over. Repository import and CI rebuild are separate work, so record what the importer skips so pipeline owners know what to recreate by hand. Confirm importer behavior against the GitLab version you will run.

Runner registration for agent replacement

TeamCity agents become GitLab Runners, which execute jobs and are distributed under the MIT license. Decide which executor each build type needs, such as shell, Docker or autoscaling, based on what the agents do today, including Windows or macOS builds and access to build tools. Keep Runner major and minor versions aligned with the GitLab instance. Plan agent-level tooling, certificates and network access before cutover, because runners will fail silently on missing dependencies that agents once provided.

CI/CD variable import through API or UI

TeamCity parameters, including those marked secret, map to GitLab CI/CD variables that can be set at instance, group or project level. Inventory every parameter and decide which ones are protected, masked or file-type, because the values themselves will not be readable from TeamCity once rebuilt. Confirm whether your team will script the import through the API or enter values through the UI, and who holds the source values during the transfer. Rotate any credential that has been exposed to a shared sheet or chat during planning.

TeamCity migration guide

GitLab's TeamCity migration guide maps build configurations to jobs in .gitlab-ci.yml, agents to runners, parameters to CI/CD variables and artifacts to the artifacts keyword. It also recommends planning plugins, agent software, shared libraries, credentials and cross-project access before any pipeline is rewritten. Use it as the checklist for the discovery phase, and confirm each mapping against your own build chains, especially templates and snapshot dependencies that do not have one-to-one equivalents.

Installation methods for the target instance

The GitLab installation methods page lists the Linux package, Helm chart, GitLab Operator, Docker and source installs that can host the target. The choice shapes how runners reach the instance, how backups run and how upgrades are staged, so decide it before pipelines are rewritten. Confirm that your chosen method fits your hosting model and any air-gapped requirements, and check the required upgrade stops for the version you deploy.

How to sequence the inventory, pilot, parallel run and cutover

The sequence moves the TeamCity estate from an unmapped set of configurations into GitLab pipelines that run beside it, one project group at a time, before TeamCity is retired. Each phase closes with a written output that the next phase depends on.

  1. Inventory build configurations, agents and dependencies

    Start with a written inventory of every build configuration, agent pool, installed plugin, shared library, credential store, parameter set, artifact dependency and cross-project trigger in TeamCity. Assign each item an owner, usually the team that maintains the project and a platform engineer for shared agents. The step is done when every configuration is listed with its triggers, its consumers and whether it is still in active use. Ask GitLab's TeamCity migration guidance which items it recommends planning first, since it lists plugins, agent software, shared libraries, credentials and cross-project access as the starting point.

  2. Decide which configurations stay, merge or retire

    Review the inventory with project owners and remove configurations that have not run recently, duplicate others or belong to retired products. Group the remaining configurations by the repositories and release trains they serve, because those groups become the cutover units later. Record the decision for each item in the migration plan, including any build that depends on a plugin with no GitLab equivalent that you will need to replace or drop. The step is done when the plan lists each retained configuration, its target project and its cutover group.

  3. Prepare the GitLab instance and runner fleet

    Confirm that the self-managed GitLab instance, its backups and its runner fleet are ready before any pipeline is written. Size runners for the build concurrency the inventory shows, choose executors that match the build environments (shell, Docker or autoscaling), and align Runner versions with the GitLab version as the Runner documentation advises. Set up CI/CD variables with protected and masked settings for the credentials identified in step one, and confirm network paths from runners to repositories, artifact stores and deployment targets. The step is done when a test job runs on each runner type and a backup and restore has been verified on the target instance.

  4. Pilot a pipeline on a low-risk project

    Select one project with a simple build, few dependencies and a team willing to give feedback. Translate its build configuration into a .gitlab-ci.yml file, mapping build steps to jobs, parameters to CI/CD variables and produced files to the artifacts keyword. Run the pipeline on feature branches and compare its outputs with TeamCity for the same commits. The step is done when the pilot project builds reliably on GitLab, the team has reviewed the pipeline and the differences have been documented and accepted or fixed.

  5. Run both systems in parallel on the same commits

    For each cutover group, let TeamCity and GitLab CI/CD build the same commits for an agreed period. Compare build status, test results, artifact checksums and deployment behavior, and track every mismatch in a shared log with an owner. Keep TeamCity as the source of release artifacts until the parallel results match. The step is done when the mismatch log is empty or every open item has a documented decision, and the release owner signs off that GitLab output is fit for the group's releases.

  6. Cut over each project group

    Move one cutover group at a time by switching its triggers, deployment jobs and release steps to GitLab, then disabling the matching TeamCity configurations. Keep the TeamCity configuration paused rather than deleted so the team can revert quickly. Confirm that notifications, branch protection and access controls work for the group before moving the next one. The step is done when the group has run through at least one normal release on GitLab and the rollback path has been tested.

  7. Decommission TeamCity after the retention period

    Once every group is live on GitLab, agree a retention period for TeamCity build history, artifacts and configuration exports with the audit and compliance owners. Export the configuration, logs and artifacts you must keep in a readable form, then stop agents, revoke service credentials and shut down the server. The step is done when the export is stored under the retention policy, access is revoked and the decommission is recorded as a change in the GitLab system of record.

How TeamCity agents become GitLab runners

Most TeamCity estates start with agents installed directly on virtual machines, often one agent per machine with build tools installed by hand. In GitLab, the closest equivalent is a Runner registered with the shell executor, which runs job commands directly on the host under the runner's user account. That keeps the mental model close to the old agent, but it also means every job shares the same operating system state, installed SDKs and cached files, so builds can affect each other.

  • Executor choice: The shell executor is the nearest match for a direct VM agent. The GitLab Runner documentation describes the available executors, and you should confirm which one fits each pool before registering anything.
  • Windows pools: Confirm the Runner version and the shell available on Windows hosts, and check how your existing PowerShell or batch steps translate into job scripts.
  • Version alignment: Keep the Runner's major and minor versions aligned with your self-managed GitLab instance. Plan the Runner upgrade alongside every GitLab upgrade.
  • Dependencies: List compilers, SDKs, certificates and licenses installed on each agent, and decide whether they stay on the host or move into images.
  • Secrets: Identify which credentials agents hold locally, such as deploy keys or signing certificates, and decide whether they move to CI/CD variables or a secrets manager.

Before cutover, ask your team to confirm which build tools exist on each VM and which of them are undocumented, because those are the first items to break on a shell runner.

What drives the cost and duration of the migration

This table lists the TeamCity characteristics that move the effort of a GitLab CI/CD migration and who pays for each piece of work. Read it as a checklist for the figures to bring to a quote: the more build configurations, agents, custom steps and sign-off teams you have, the more planning and validation the work needs. Most of the effort is one-time, while runner patching and GitLab upgrades on required stops recur.

DriverWhy it changes effortHow to keep it down or what to ask for
Build configurations and dependency chainsEach configuration becomes a job or pipeline, and snapshot dependencies must be re-expressed as needs or stagesAsk for a count of configurations and a map of which ones trigger others
Agents and OS varietyEach agent pool type needs a matching runner, image or executor, and tooling must be rebuilt or containerizedGroup agents by OS and toolchain, and ask how many distinct images the quote assumes
Plugins and custom build stepsSteps with no direct GitLab equivalent need scripts, images or templates written and tested by handInventory every plugin and custom runner step early and decide replace, script or retire
Shared libraries and templatesShared build logic must be turned into GitLab includes, components or project templatesAsk whether shared logic is consolidated first, since fewer shared sources reduce rewrite work
Credentials and secretsStored passwords, tokens and connection settings must be moved to CI/CD variables or an external secrets manager and rotatedAsk who holds the credential inventory and whether rotation is in scope
Cross-project access and artifact dependenciesProjects that pull artifacts or build outputs from one another need permissions and job-artifact flows redesignedMap every cross-project dependency and confirm which teams own each side
Teams that must sign off on cutoverEach owning team reviews pipelines, approves cutover dates and tests deployments, which adds coordination timeAsk the vendor to list sign-off roles and how many rounds of review the quote includes
Parallel run requirementRunning TeamCity and GitLab side by side doubles some build and deployment work until confidence is reachedDecide early whether a parallel run is required and for how many pipelines
One-time workPipeline rewrite, runner build-out, secrets setup, validation and cutover planningRequest a fixed-scope plan with deliverables per phase, as most engagements are fixed-scope
Recurring workRunner patching, runner and GitLab version alignment, and GitLab upgrades that must pass through required upgrade stopsConfirm who patches runners and who tests each upgrade, and whether a retainer covers it

What usually goes wrong and how to prevent it

Most TeamCity to GitLab migrations fail on details that were never written down: a plugin nobody inventoried, a token pasted into a variable, or a pipeline that still runs in the old system. The cards below cover the risks we see most often and one prevention step for each. Work through the inventory before rewriting any pipeline.

Plugins and agent software without equivalents

TeamCity plugins and custom agent tools often hold build steps, notifications or code signing that have no direct GitLab counterpart. They tend to surface late, when a pipeline fails on a missing tool. Inventory every plugin, agent-installed binary and shared library before writing .gitlab-ci.yml, then decide for each whether to replace it with a script, a container image or a component. Ask the GitLab migration guide what it recommends for plugins and agent software before you plan.

Secrets copied into CI/CD variables

Teams often move TeamCity password parameters into GitLab CI/CD variables with the same values and broad scope. Unmasked or unprotected variables can then appear in job logs or reach branches that should never see production credentials. Classify each parameter as a secret, a configuration value or a deployment credential, then set masking, protection and environment scope per variable. Confirm where long-lived credentials should move to an external secrets manager instead.

Hidden cross-project dependencies

A TeamCity snapshot dependency or shared artifact reference can connect projects that nobody documented as linked. When one pipeline moves and the other stays behind, the build fails only on cutover day. Map every snapshot dependency, artifact dependency and cross-project credential before you move the first project. Then migrate dependent projects as a group and test each chain end to end in a staging GitLab instance.

Artifact retention differences

TeamCity and GitLab handle artifact lifetimes differently, so builds that once kept outputs for months may lose them early after the move. Teams then discover that release evidence or rollback images are gone. Record the retention rules you rely on today, set expire_in explicitly on each artifact, and check the instance-level and project-level settings your administrators control. Make sure release artifacts you must keep are stored in a system you control, not only in pipeline history.

Runner versions drifting from GitLab

Runners installed on agent hosts are often left at old versions because nobody owns them after cutover. GitLab recommends keeping Runner major and minor versions aligned with the GitLab instance, and drift causes jobs to fail or behave unpredictably. Assign an owner for the runner fleet, pin runner versions in your provisioning code, and include Runner upgrades in each GitLab upgrade plan. Check the GitLab Runner documentation for the supported version pairing before you install.

Parallel runs that double-deploy

During a transition, both TeamCity and GitLab can build the same commit, and a deployment step in each can release the same change twice. This risk grows when triggers still watch the same branches. Disable TeamCity triggers and deployment steps project by project as each GitLab pipeline takes over, and use protected environments and deployment approvals in GitLab to prevent duplicate releases. Keep a dated cutover log for each project so the team can see which system owns its deploys.

Questions teams ask before moving from TeamCity to GitLab CI/CD

What does a TeamCity to GitLab CI/CD migration cost, and what drives it?

The cost depends on how many build configurations, templates, shared libraries, plugins and deployment targets you run, and on how many of them need rebuilding rather than copying. Each configuration maps to jobs in .gitlab-ci.yml, so the count and complexity of your projects matter more than the number of servers. Ask for a written scope that lists the configurations in each wave, the agents and runners to be provisioned, the credentials and cross-project access to rebuild, and the validation each pipeline must pass before cutover. Separate one-time work (inventory, pipeline rewrites, runner setup, cutover) from recurring costs such as runner compute, GitLab licensing and support. GitLab's pricing page lists Free at 0 US dollars and Premium at 29 US dollars per user per month billed annually, with Ultimate custom priced, so licensing needs its own line in the quote.

How long does a TeamCity to GitLab migration take?

Duration is set by the number of pipelines, how many share logic, and how much validation your release process requires. Teams with a small number of projects and simple deployments move faster than teams with dozens of templated build chains, custom plugins and production deployment gates. The planning stage that GitLab recommends, covering plugins, agent software, shared libraries, credentials and cross-project access, is often where the schedule is won or lost, so ask for it to be a named phase with its own deliverable. Request a timeline in the written scope with milestones per wave, the point at which each project's pipeline must pass in parallel, and the decision gates for moving to production. No duration is given here because none has been researched for this topic, so confirm it against your own inventory.

What does our internal team need to provide during the migration?

Your team owns the knowledge of what the pipelines are supposed to do, so it must provide access and decisions that a partner cannot infer from the configuration alone. Typical inputs include:

  • An export or read access to all TeamCity build configurations, templates, parameters and agent pools
  • The list of plugins, custom build steps and shared libraries in use
  • Credentials owners, secret rotation policy and cross-project dependencies
  • Named approvers for deployment environments and release windows
  • Test environments where pipelines can run without touching production

A written scope should name who on your side signs off each wave and how long reviews may take, so that work does not stall waiting for answers.

Can our own team run this migration without a partner?

Yes, a capable internal team can run the migration if it has people who know GitLab CI/CD, can operate runners, and have time to rewrite and test pipelines alongside their normal work. The main risks are not technical syntax but missed dependencies, such as an agent-specific tool, a credential used by several builds, or a deployment step that only worked because of a plugin. A partner can take on the inventory, the rewrite of a defined set of pipelines, runner design and the cutover checks as a fixed-scope engagement, leaving your team to own the decisions. Compare the two options by listing the work, the skills you already have, and the people you can release for the period, then ask a partner for a written scope that matches that gap.

Do TeamCity build configurations convert to GitLab automatically?

No. GitLab's TeamCity migration guidance maps the concepts by hand: build configurations become jobs in .gitlab-ci.yml, parameters become CI/CD variables, and artifacts are declared with the artifacts keyword. Build chains, snapshot dependencies, triggers and templates need to be re-expressed using GitLab's pipeline structure, and any TeamCity-specific build feature needs a replacement or an explicit decision to drop it. Expect to review each converted pipeline for behavior, not just syntax. Ask for the mapping of every configuration type you use to its GitLab equivalent in the scope, along with the test method for each.

How do GitLab Runners replace TeamCity agents?

GitLab Runner is the application that executes CI/CD jobs, so it takes the role TeamCity agents played. It supports shell, Docker and autoscaling executors across clouds and hypervisors, which means the design choice is how jobs are isolated and how capacity scales. Keep the Runner major and minor versions aligned with GitLab, and plan runner tags so jobs land on the right machines, such as those with access to a specific network or a signing key. Agent software, installed tools and shared machines often hide dependencies, so inventory them before provisioning. Confirm the executor model and isolation requirements in your written scope, because they affect security review and cost.

Do we need to run TeamCity and GitLab in parallel?

In most regulated or release-critical environments, running both systems for a period is the safer approach, because it lets you compare results and roll back without losing build history. The pipelines should produce matching artifacts and test results on the same inputs before the TeamCity builds are retired. Parallel running also costs runner capacity and duplicated maintenance, so define which projects run in parallel, for how long, and who decides when each one switches. Ask for the parallel-run criteria, the rollback path for each wave and the retirement date for TeamCity agents in the written scope.

Where to read the official TeamCity migration guidance

Read the GitLab Docs guide Migrate from TeamCity before you estimate the migration or write any .gitlab-ci.yml file, because it sets the mapping that this page assumes: build configurations become jobs, agents become runners, parameters become CI/CD variables and artifacts move to the artifacts keyword. Treat that mapping as the starting point for your inventory, not as proof that your builds will translate one for one. The guide also recommends planning first for plugins, agent software, shared libraries, credentials and cross-project access, so those items should be listed before anyone touches a pipeline.

Confirm current behavior against the guide before you scope. GitLab updates its documentation with each release, and the GitLab release cadence means a page you read last quarter may describe a different set of keywords or steps. Check the date on the guide, note the GitLab version your self-managed instance runs, and ask the partner or your own engineers to verify each TeamCity feature in your inventory against that version. Where the guide is silent, such as a specific plugin or a custom build feature, record the gap as an open question rather than an assumption.

The second next read is the GitLab Runner documentation, which you need once you decide how agents will be replaced. Runners execute the jobs, so their executor choice, isolation model and version alignment with GitLab determine whether your migrated pipelines behave like the TeamCity builds they replace. Read it alongside the guide, not after it, because runner decisions often change the shape of the jobs you write.

How DeployOpen scopes and delivers the TeamCity migration

DeployOpen plans the move from TeamCity to GitLab CI/CD before any pipeline is rewritten, starting with an inventory of plugins, agent software, shared libraries, credentials and cross-project access. We then map build configurations, agents, triggers, parameters and artifacts to GitLab jobs, runners and CI/CD variables, and deliver the result inside infrastructure you control.

How we scope

  • We inventory TeamCity build configurations, templates, agents, triggers and parameters before agreeing the written scope.
  • We confirm which plugins, shared libraries and credentials each pipeline depends on, and which need a GitLab equivalent.
  • Engagements are fixed-scope, with deliverables and timelines agreed in writing before the migration work starts.

How we build

  • We map build configurations to jobs in .gitlab-ci.yml and parameters to CI/CD variables, with protected and masked settings where needed.
  • We design the runner fleet, executor types and agent replacements, and test each migrated pipeline against its TeamCity baseline.
  • We check artifact handling, cache behavior and cross-project access in a non-production GitLab project before any cutover.

How we hand over

  • We document the mapping for each build configuration, including what changed, what was retired and what needs owner sign-off.
  • We walk your engineers through runner operations, variable ownership and how to add new pipelines using the agreed patterns.
  • We record open items, such as plugin functions with no direct equivalent, so your team can decide how to handle them.

How we support

  • Ongoing support, runner maintenance and pipeline changes after handover are available as a retainer.
  • Retainers can cover GitLab and Runner upgrades, so runner and server versions stay aligned as releases move forward.
  • Ask whether the retainer includes pipeline reviews, runner capacity changes and help with the next GitLab upgrade stop.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.