{"id":405,"date":"2026-10-14T03:21:07","date_gmt":"2026-10-14T03:21:07","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2015\/02\/24\/build-configuration-templates-in-teamcity\/"},"modified":"2026-10-14T03:21:07","modified_gmt":"2026-10-14T03:21:07","slug":"build-configuration-templates-in-teamcity","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/build-configuration-templates-in-teamcity\/","title":{"rendered":"TeamCity Meta-Runners Guide: Reusable Build Steps vs Build Templates"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Originally published on 2015-02-24; fully revised and updated.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">TeamCity Meta-Runners let you package repeated build logic into reusable runner types. If you maintain multiple build configurations and keep copying the same steps, this pattern helps you centralize those steps, expose only the parameters that vary, and keep your CI setup easier to maintain.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2015\/02\/build-configuration-templat.png\" alt=\"Build configuration templates in TeamCity\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">What Meta-Runners solve in TeamCity<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Standard build runners are convenient, but teams often end up duplicating identical step sequences across many build configurations. Meta-Runners address this by turning existing build steps into a reusable custom runner. You can then add that custom runner wherever needed instead of recreating the same commands repeatedly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Templates vs Meta-Runners vs command-line steps<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">These options are related, but they solve different reuse problems:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Option<\/th><th>Best for<\/th><th>Reuse scope<\/th><th>Key limitation<\/th><\/tr><\/thead><tbody><tr><td>Build configuration template<\/td><td>Standardizing mostly similar build configurations<\/td><td>Whole configuration baseline<\/td><td>A build configuration can be based on only one template<\/td><\/tr><tr><td>Meta-Runner<\/td><td>Reusing one or more repeated build steps<\/td><td>Build-step level across many configurations<\/td><td>Needs deliberate parameter design to stay generic<\/td><\/tr><tr><td>Command-line runner only<\/td><td>Quick one-off scripts<\/td><td>Single step in a single configuration<\/td><td>Duplication and drift when copied across projects<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Convert a fixed deploy command into a reusable step<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The original example starts with a command-line runner that deploys to one specific Heroku remote:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs language-bash\">git remote add heroku git@heroku.com:django-ci-example.git\ngit push heroku master<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">To make this reusable, extract the remote URL into a TeamCity parameter:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css language-bash\"><span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">remote<\/span> <span class=\"hljs-selector-tag\">add<\/span> <span class=\"hljs-selector-tag\">heroku<\/span> %<span class=\"hljs-selector-tag\">heroku<\/span><span class=\"hljs-selector-class\">.remote<\/span>%\n<span class=\"hljs-selector-tag\">git<\/span> <span class=\"hljs-selector-tag\">push<\/span> <span class=\"hljs-selector-tag\">heroku<\/span> <span class=\"hljs-selector-tag\">master<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">You then provide <strong>%heroku.remote%<\/strong> in the build parameters for each consuming build configuration.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Extraction and reuse workflow<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In the original TeamCity flow, you parameterize the step first, then use <strong>Extract Meta-Runner<\/strong> from the build configuration settings.<\/p>\n\n\n\n<pre class=\"mermaid\">\nflowchart TD\n    A[Open build configuration] --> B[Parameterize fixed values]\n    B --> C[Validate command line step]\n    C --> D[Click Extract Meta-Runner]\n    D --> E[Name and save Meta-Runner]\n    E --> F[Open another build configuration]\n    F --> G[Add build step with Meta-Runner type]\n    G --> H[Set heroku.remote value]\n    H --> I[Run build and verify]\n<\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>Create or update the original build step so variable values are parameters.<\/li><li>Extract a Meta-Runner from that build configuration.<\/li><li>Edit the generated Meta-Runner if you want fewer parameters or steps.<\/li><li>Add the Meta-Runner as a normal runner type in other build configurations.<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2015\/02\/Going-meta-with-Meta-Runners-in-teamcity1.jpg\" alt=\"Extract Meta-Runner dialog in TeamCity\"\/><figcaption>Extract Meta-Runner dialog from the original walkthrough.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Using the Meta-Runner in other build configurations<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After extraction, the new runner appears in the <strong>Runner type<\/strong> list when adding build steps. When selected, the exposed parameter fields (for example, <strong>heroku.remote<\/strong>) can be set per build configuration. This preserves step behavior while removing copy-paste maintenance.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2015\/02\/Going-meta-with-Meta-Runners-in-teamcity3.jpg\" alt=\"Meta-Runner available in TeamCity runner type list\"\/><figcaption>The extracted Meta-Runner becomes selectable like any built-in runner type.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A useful detail from the original guide: a Meta-Runner is stored as XML and can be edited in TeamCity. You can remove default parameter values if you want users to provide explicit values each time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Security and maintainability notes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The original article notes that deploying to Heroku through git remotes requires SSH keys on the agent, and that this example is primarily instructional rather than an ideal production deployment pattern. Treat runner extraction as the key concept, and apply your organization\u2019s secret-handling and deployment controls.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Original references preserved from the source material: <a href=\"http:\/\/techbus.safaribooksonline.com\/9781849699518\/ch03_html\">Chapter 3<\/a>, <a href=\"http:\/\/techbus.safaribooksonline.com\/9781849699518\/ch06_html\">Chapter 6<\/a>, and <a href=\"https:\/\/github.com\/moredip\/heroku-headless\">heroku-headless<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Common pitfalls<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Leaving environment-specific values hardcoded instead of parameterized.<\/li><li>Using a template when only step-level reuse is needed.<\/li><li>Extracting too many unrelated steps into one Meta-Runner.<\/li><li>Keeping risky default parameter values that are easy to forget to override.<\/li><li>Ignoring agent prerequisites such as SSH key availability for git-based deploys.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Attribution:<\/strong> Based on the original DevOpsSchool post and its referenced material from <em>Learning Continuous Integration with TeamCity<\/em>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how TeamCity Meta-Runners help you eliminate duplicated build steps across configurations. This guide compares templates vs Meta-Runners and walks through a parameterized Heroku deploy example.<\/p>\n","protected":false},"author":1,"featured_media":3513,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[2],"tags":[91,1753,1766,1767,679,282,144,1769,1768,315],"class_list":["post-405","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorised","tag-build","tag-build-configuration","tag-build-configuration-templates","tag-build-configuration-templates-in-teamcity","tag-build-management","tag-configuration","tag-teamcity","tag-teamcity-guide","tag-teamcity-tutorial","tag-templates"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/405","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=405"}],"version-history":[{"count":4,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/405\/revisions"}],"predecessor-version":[{"id":79272,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/405\/revisions\/79272"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/3513"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=405"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=405"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=405"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}