Configuration parameters, system properties, environment variables, predefined TeamCity params, password masking, typed and prompt parameters, inheritance, and cross-chain dep.* parameter passing
TeamCity has three distinct parameter kinds. They differ in scope and how they surface in build steps:
| Kind | Prefix | Access in build | Use for |
|---|---|---|---|
| Configuration Parameter | (none) | %param.name% in TC config fields only — NOT automatically in build steps as env vars | Teamcity-internal values: artifact paths, step flags, build number tokens |
| System Property | system. | Passed as -Dprop.name=value to Maven/Ant runners automatically; accessible as %system.prop.name% | Java system properties for Maven/Ant builds |
| Environment Variable | env. | Passed as OS environment variable $PROP_NAME or %PROP_NAME% to all build steps | Secrets, tool paths, deployment targets — anything a shell script reads from the environment |
A common mistake: defining a value as a Configuration Parameter and then trying to read it in a shell script with $MY_PARAM. Configuration parameters are only substituted into TeamCity config fields (step runner settings, artifact paths, etc.) — they do NOT become environment variables. To use a value in a shell script, define it as an Environment Variable (env.MY_PARAM).
TeamCity provides dozens of built-in parameters. The most useful ones:
| Parameter | Example value | Description |
|---|---|---|
%build.number% | 1.2.42 | The current build number (from the format template) |
%build.id% | 12345 | Internal TeamCity build ID (unique across all builds) |
%build.counter% | 42 | Auto-incrementing build counter for this config |
%teamcity.build.branch% | feature/login | Short branch name (without refs/heads/ prefix) |
%teamcity.build.branch.is_default% | true | Whether this build is on the default branch |
%build.vcs.number% | a3f2c91d | VCS revision (Git SHA) checked out |
| Parameter | Example value |
|---|---|
%teamcity.agent.name% | Agent-Linux-01 |
%teamcity.agent.work.dir% | /opt/buildagent/work |
%teamcity.agent.home.dir% | /opt/buildagent |
%teamcity.agent.os.name% | Linux |
| Parameter | Example value |
|---|---|
%teamcity.serverUrl% | https://ci.yourcompany.com |
%teamcity.build.id% | 12345 |
%system.teamcity.buildType.id% | BackendServices_Build |
Parameter references use %param.name% syntax and are substituted at build time. They work in:
# In Maven runner Goals:
clean package -Dapp.version=%build.number%
# In artifact paths:
target/myapp-%build.number%.jar => artifacts
# In build number format:
1.0.{build.counter}.%build.vcs.number%
# In a Command Line script:
echo "Deploying %build.number% to %deploy.target%"
echo "Branch: %teamcity.build.branch%"
# Parameter referencing another parameter:
# env.DEPLOY_URL = https://%deploy.host%/api
# (deploy.host is another config parameter)
If you reference %my.param% but it's not defined anywhere, TeamCity leaves the literal string %my.param% in the value — it does not fail or warn. This silently passes a broken value to your build step. Always check the build log's Parameters tab to verify parameter values were substituted correctly.
Sensitive values (API keys, database passwords, deployment credentials) should be stored as password-type parameters so they are masked in build logs.
env.DEPLOY_API_KEYTeamCity replaces every occurrence of the password value in build log output with ***. This works for most cases but can be bypassed if the script base64-encodes the value, splits it across multiple echo statements, or outputs it indirectly. For very sensitive secrets (production database passwords), additionally restrict which users can view the build configuration and edit parameters.
Project administrators can see password parameter values in the TeamCity UI by going to the parameter's edit page. Password params protect against accidental log exposure, not against intentional access by admins. For genuinely secret values accessible only to the CI system, consider using an external secret manager (HashiCorp Vault, AWS Secrets Manager) and injecting secrets at runtime via a build step, not as TC parameters.
Parameters can be given a type, label, and description — this makes the manual build run dialog user-friendly and validates input before the build starts.
| Type | UI control | Use case |
|---|---|---|
| Text | Text input | Free-text values, version strings |
| Password | Masked text input | Secrets, tokens |
| Checkbox | Checkbox (true/false) | Feature flags: deploy.to.production |
| Select list | Dropdown menu | Environment: staging / production / qa |
# Example: Select list parameter for deployment environment
Name: deploy.environment
Kind: Configuration parameter
Type: Select (allowed values: staging, production, qa)
Default: staging
Label: Deployment Environment
Description: Target environment for this deployment
Display: prompt <-- shown in Run dialog, must be filled in
When a parameter's Display is set to prompt, the manual run dialog requires the user to provide a value before the build starts. This creates semi-interactive deployment builds that are safe because the user must consciously choose the target.
# Good use case: deployment build config
Parameters:
env.DEPLOY_TARGET = (blank, type=text, display=prompt, label="Target host")
env.DEPLOY_VERSION = %build.number% (type=text, display=normal)
env.ENVIRONMENT = (type=select, values=[staging,production], display=prompt)
env.CONFIRMED = (type=checkbox, display=prompt, label="I confirm production deploy")
The CONFIRMED checkbox means a developer accidentally clicking Run can't accidentally deploy to production — they see a checklist they must fill in.
Parameters are inherited from parent to child. The most specific definition wins:
# Resolution order (later overrides earlier):
# 1. Predefined TeamCity parameters (teamcity.*, build.*)
# 2. Root Project parameters
# 3. Parent Project parameters
# 4. Current Project parameters
# 5. Build Configuration parameters
# 6. Build step runner fields
# Example: env.NEXUS_URL defined at project level
# A child build config can override it for a specific config
# by defining env.NEXUS_URL at the build config level
To see all resolved parameters for a specific build: open the build → Parameters tab. Shows every parameter and its final resolved value, including which level it came from.
When build configurations are chained via snapshot dependencies (Phase 9), a downstream build can read parameters from any upstream build using the dep. prefix.
# Syntax:
# dep.UPSTREAM_BUILD_CONFIG_ID.PARAMETER_NAME
# Example: Deploy config reads the version from the Build config
dep.BackendServices_Build.build.number
# Or a custom parameter published by Build:
dep.BackendServices_Build.app.artifact.version
# Use in a deploy step:
echo "Deploying version: %dep.BackendServices_Build.build.number%"
ssh deploy@server.com "deploy.sh --version=%dep.BackendServices_Build.build.number%"
dep.* parameters are only resolved when there is a snapshot dependency between the two build configs. If you use the dep. prefix without a snapshot dependency, the parameter resolves to the literal string dep.BuildConfig.param — silently wrong. You cannot use dep.* across a Finish Build Trigger boundary.
Create a dynamic version number using the build counter, VCS branch name, and Git SHA:
# Build number format (General Settings):
{build.counter}
# Parameter: app.version (Configuration parameter)
# Value: 1.2.%build.counter%
# Parameter: app.full.version (Configuration parameter)
# Value: %app.version%+%build.vcs.number%.%teamcity.build.branch%
# Result for build #42 on feature/login at sha abc123:
# app.version = 1.2.42
# app.full.version = 1.2.42+abc123.feature/login
# Use in Maven step:
# Goals: clean package -Dapp.version=%app.version%
# Artifact paths:
# target/myapp-%app.version%.jar => artifacts