Migrate from TeamCity to GitHub Actions: Step-by-Step
Moving from TeamCity to GitHub Actions is mostly a translation job: Build configuration become workflows and jobs. This guide maps the concepts and shows the before/after.
TeamCity and GitHub Actions share the same primitives - pipelines, jobs, and steps - under different names. The migration is methodical: translate the config, port secrets and caching, and verify in parallel before cutting over.
Concept mapping
| TeamCity | GitHub Actions |
|---|---|
| Build configuration | Workflow (.github/workflows/*.yml) |
| build step | Job (jobs.<id>) |
| Step / command | Step (run: or uses:) |
| Typed parameters / tokens | Encrypted secrets / variables |
| Artifact dependencies / cache | actions/cache |
| Agent / executor | Runner (runs-on:) |
Before and after
object Build : BuildType({
steps {
script { scriptContent = "npm ci && npm test" }
}
triggers { vcs {} }
})The GitHub Actions equivalent
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm testMigration steps
- Inventory your TeamCity pipelines and list every job, trigger, and secret.
- Create
.github/workflows/ci.ymland translate one pipeline at a time. - Move secrets into GitHub Actions encrypted secrets (port build chains and parameters).
- Add
actions/cachefor dependencies to match prior build speed. - Run the new workflow in parallel with the old pipeline on a branch and compare results.
- Cut over once green, then archive the old config.
Common pitfalls
- TeamCity build chains (snapshot dependencies) map to
needs:between jobs. - Kotlin/XML DSL has no direct port - re-express logic as ordered
run:steps and reusable workflows. - TeamCity agents are long-lived; GitHub runners are ephemeral, so do not rely on persisted agent state.
After you migrate: cut cost and flakiness
Once on GitHub Actions, the next wins are cost and reliability. Managed runners like Latchkey run the same workflows at roughly 69% lower per-minute cost than GitHub-hosted, warm pools remove queue time, and self-healing retries transient failures automatically - so the pipeline you just migrated stays green and cheap. The switch is usually a one-line runs-on: change.
Key takeaways
- Build configuration map cleanly to GitHub Actions workflows.
- Port secrets and caching to match speed and security.
- Run both pipelines in parallel before cutting over.
- Then move to managed runners to cut cost and flaky re-runs.