TeamCity
CI/CD Tool
TeamCity
Overview
TeamCity is JetBrains' commercial CI/CD server. It features powerful build management, IntelliJ integration, and rich enterprise features, enabling modern DevOps through Kotlin DSL configuration and Docker/Kubernetes support.
Details
TeamCity is a commercial CI/CD automation server developed by JetBrains, expanding adoption in enterprise environments since its initial release in 2006. TeamCity 2025.03 was released in 2025, achieving significant UI updates through TeamCity/Pipelines integration, enhanced Docker/Podman support, and improved Perforce integration. While other CI/CD tools use YAML, TeamCity adopts Kotlin DSL, providing strong type safety and excellent developer experience. Tight integration with IntelliJ IDEA, Rider, and Visual Studio enables developers to interact directly with CI/CD systems from their IDEs. Intelligent build features automatically detect repository changes and trigger appropriate build steps, supporting incremental builds, dependency-based caching, and test history tracking. Kubernetes support dynamically launches build agents based on workload, with access to nearly all functionality through RESTful APIs. The free version supports up to 100 build configurations and 3 agents, including all enterprise features.
Pros and Cons
Pros
- Kotlin DSL Configuration: Type-safe configuration without YAML
- Powerful IDE Integration: IntelliJ, Rider, Visual Studio integration
- Intelligent Builds: Automatic change detection and build triggering
- Enterprise Features: Advanced security and governance
- Docker/Kubernetes Support: Native container support
- Rich VCS Integration: Git, Perforce, Mercurial support
- Detailed Reporting: Comprehensive build analysis and metrics
- Free Version Features: All features available up to 100 configurations
- Experimental Kubernetes Executor: Native K8s pod execution
Cons
- License Costs: High costs for large environments
- Learning Curve: Kotlin DSL and proprietary concepts
- JetBrains Ecosystem Dependency: Constraints in non-JetBrains IDE environments
- Server Management: On-premises operation management overhead
- Resource Consumption: High memory and CPU usage
- Cloud Limitations: Limited fully managed service options
- Community Size: Smaller community compared to open-source competitors
Key Links
- TeamCity Official Site
- TeamCity Features
- TeamCity Documentation
- TeamCity 2025.03 What's New
- TeamCity Cloud
- TeamCity REST API
Code Examples
Basic Kotlin DSL Configuration
// .teamcity/settings.kts
version = "2024.03"
project {
buildType(Build)
buildType(Test)
buildType(Deploy)
}
object Build : BuildType({
name = "Build"
vcs {
root(DslContext.settingsRoot)
}
steps {
script {
name = "Install Dependencies"
scriptContent = """
npm ci
npm run build
""".trimIndent()
}
}
triggers {
vcs {
branchFilter = "+:*"
}
}
features {
dockerSupport {
loginToRegistry = on {
dockerRegistryId = "myregistry"
}
}
}
})
object Test : BuildType({
name = "Test"
dependencies {
snapshot(Build) {
onDependencyFailure = FailureAction.FAIL_TO_START
}
}
steps {
script {
name = "Run Tests"
scriptContent = """
npm test
npm run test:integration
""".trimIndent()
}
}
features {
coverage {
tool = jacoco
rules {
rule {
minValue = 80
metric = LINES
}
}
}
}
})
Docker Integration and Multi-platform
// .teamcity/settings.kts
object DockerBuild : BuildType({
name = "Docker Build"
params {
param("docker.image.name", "myapp")
param("docker.registry", "myregistry.azurecr.io")
}
steps {
dockerCommand {
name = "Build Docker Image"
commandType = build {
source = file {
path = "Dockerfile"
}
namesAndTags = "%docker.registry%/%docker.image.name%:%build.number%"
commandArgs = "--platform linux/amd64,linux/arm64"
}
}
dockerCommand {
name = "Push Docker Image"
commandType = push {
namesAndTags = "%docker.registry%/%docker.image.name%:%build.number%"
}
}
}
features {
dockerSupport {
loginToRegistry = on {
dockerRegistryId = "azure-registry"
}
}
buildCache {
use {
rules = """
+:**/node_modules
+:**/dist
""".trimIndent()
}
publish {
rules = """
+:**/node_modules
+:**/dist
""".trimIndent()
}
}
}
})
Kubernetes Deployment
// .teamcity/settings.kts
object KubernetesDeploy : BuildType({
name = "Deploy to Kubernetes"
params {
param("k8s.namespace", "production")
param("k8s.cluster", "production-cluster")
param("app.image", "%docker.registry%/%docker.image.name%:%build.number%")
}
dependencies {
snapshot(DockerBuild) {
onDependencyFailure = FailureAction.FAIL_TO_START
}
}
steps {
script {
name = "Update Kubernetes Manifests"
scriptContent = """
sed -i 's|IMAGE_TAG|%app.image%|g' k8s/deployment.yaml
kubectl apply -f k8s/ --namespace=%k8s.namespace%
kubectl rollout status deployment/myapp --namespace=%k8s.namespace%
""".trimIndent()
}
script {
name = "Health Check"
scriptContent = """
kubectl get pods --namespace=%k8s.namespace%
kubectl logs deployment/myapp --namespace=%k8s.namespace% --tail=50
""".trimIndent()
}
}
features {
kubernetes {
connection = kubernetesConnection {
name = "k8s-connection"
apiServerUrl = "https://k8s-api.example.com"
namespace = "%k8s.namespace%"
authStrategy = token {
token = "%secure:k8s.token%"
}
}
}
notifications {
notifier = slackNotifier {
connection = slackConnection {
id = "slack-connection"
botToken = "%secure:slack.token%"
}
messageFormat = teamcityFormat()
channel = "#deployments"
}
}
}
})
Complex Workflows and Templates
// .teamcity/settings.kts
object PipelineTemplate : Template({
name = "Standard Pipeline"
params {
param("app.name", "")
param("git.branch", "main")
param("environment", "staging")
}
vcs {
root(DslContext.settingsRoot)
}
steps {
script {
name = "Setup Environment"
scriptContent = """
echo "Setting up %app.name% for %environment%"
npm ci
""".trimIndent()
}
script {
name = "Run Quality Checks"
scriptContent = """
npm run lint
npm run type-check
npm audit
""".trimIndent()
}
script {
name = "Build Application"
scriptContent = """
npm run build
tar -czf %app.name%-%build.number%.tar.gz dist/
""".trimIndent()
}
script {
name = "Run Tests"
scriptContent = """
npm test -- --coverage
npm run test:e2e
""".trimIndent()
}
}
triggers {
vcs {
branchFilter = "+:%git.branch%"
}
}
features {
pullRequests {
vcsRootExtId = "${DslContext.settingsRoot.id}"
provider = github {
authType = token {
token = "%secure:github.token%"
}
filterAuthorRole = PullRequests.GitHubRoleFilter.MEMBER
}
}
}
})
// Template usage example
object WebAppPipeline : BuildType({
templates(PipelineTemplate)
name = "Web App Pipeline"
params {
param("app.name", "webapp")
param("environment", "production")
}
})
object APIPipeline : BuildType({
templates(PipelineTemplate)
name = "API Pipeline"
params {
param("app.name", "api")
param("git.branch", "develop")
}
})
Security and Enterprise Features
// .teamcity/settings.kts
object SecurePipeline : BuildType({
name = "Production Deployment"
params {
param("env.VAULT_ADDR", "https://vault.example.com")
password("vault.token", "%secure:vault.production.token%")
}
steps {
script {
name = "Security Scan"
scriptContent = """
# SonarQube analysis
sonar-scanner \
-Dsonar.projectKey=%teamcity.project.id% \
-Dsonar.sources=src/ \
-Dsonar.host.url=%secure:sonar.url% \
-Dsonar.login=%secure:sonar.token%
# Dependency vulnerability scan
npm audit --audit-level high
# SAST scan
semgrep --config=auto src/
""".trimIndent()
}
script {
name = "Retrieve Secrets"
scriptContent = """
export VAULT_TOKEN=%vault.token%
DATABASE_URL=$(vault kv get -field=url secret/app/database)
API_KEY=$(vault kv get -field=key secret/app/api)
echo "##teamcity[setParameter name='env.DATABASE_URL' value='$DATABASE_URL']"
echo "##teamcity[setParameter name='env.API_KEY' value='$API_KEY']"
""".trimIndent()
}
}
features {
approvals {
approval {
approvalRules = "user:admin,user:manager"
timeout = 3600
}
}
investigations {
defaultAssignee = user("teamlead")
defaultResponsible = user("devops")
}
}
requirements {
contains("teamcity.agent.os.name", "Linux")
moreThan("teamcity.agent.hardware.memorySizeMb", "4096")
}
})