Most network teams end up in one of two places. The first is full manual: every switch gets configured by hand, every change is a SSH session, and consistency depends entirely on whoever is doing the work that day. The second is a project that tried to fix that problem and went too far: a half-deployed Ansible framework that three people understand, a Python script library that nobody documents, or a NetOps platform that took eight months to build and now nobody maintains. Both of these outcomes are real, both are painful, and the irony is that most teams have access to a middle path they don't fully use.
Catalyst Center CLI templates sit squarely in that middle path. They are not a full automation framework. They do not replace Ansible or Python for complex workflows. But for the bulk of what campus and enterprise network teams actually do day to day, they are genuinely practical: repeatable provisioning, consistent configuration, and reusable logic that does not require anyone on the team to be a developer. This article is a practitioner-level look at how to use them well, where they fall apart, and how to adopt them without creating new fragility in the process.
The Automation Trap Most Teams Fall Into
The fully manual model has an obvious cost: speed, consistency, and operator error. Every engineer who configures a switch has their own conventions. VLANs get numbered differently. NTP servers get set inconsistently. Logging destinations vary. AAA config drifts over time. None of this is catastrophic individually, but it accumulates. When you need to make a change across 150 switches, inconsistency is the thing that turns a one-hour change window into a three-hour incident.
The overcorrection is just as common. A team decides to "do automation properly" and starts building infrastructure around it: Ansible roles, Git repositories, CI pipelines, variable files per site, per-device inventory. This is genuinely the right model at a certain scale, but it carries a real cost of its own. Someone has to maintain the tooling, test it, handle Python dependency upgrades, manage SSH key rotation, and document it well enough that the next engineer can actually use it. For a team of three people managing 200 switches who also run helpdesk escalations and are responsible for the WAN, that investment is often not sustainable.
CLI templates in Catalyst Center do not require you to operate a CI pipeline or learn Ansible modules. The templating logic runs inside Catalyst Center. Variables get filled in through the UI or via API. Devices get configured through the existing management infrastructure you already have. That narrower scope is not a limitation; for many teams, it is exactly the right fit.
What CLI Templates Are in Catalyst Center
A CLI template in Catalyst Center is a text block of IOS/IOS-XE commands with substitution variables. When you apply a template to a device, Catalyst Center resolves the variables, generates the final CLI, and pushes it over SSH or NETCONF. That is the core of it. The complexity lives in the details of how variables work, how templates are structured, and when they run.
Catalyst Center distinguishes between two categories of templates based on when in the device lifecycle they run:
| Category | When it runs | Common use cases | Trigger |
|---|---|---|---|
| Day 0 (Onboarding) | During initial device provisioning via Plug and Play (PnP) | Initial hostname, management IP, AAA, NTP, SSH, base ACLs, SNMP | PnP workflow; device contacts Catalyst Center during first boot |
| Day N (Provisioning) | After a device is already under management | VLAN additions, interface configuration, ACL updates, routing changes, policy changes | Manual trigger from the Catalyst Center UI, API call, or network profile association |
Day 0 templates handle the foundational configuration that every device needs to be manageable. Day N templates handle everything after that: ongoing operations, incremental changes, and policy updates. In practice, your Day 0 template should be relatively stable (you are not changing your management model constantly), and your Day N template library is what grows over time.
Within these categories, Catalyst Center also supports Composite Templates, which are wrappers that sequence multiple regular templates into a logical flow. If you have a base infrastructure template, a site-specific template, and a role-specific template (access vs. distribution), a composite template lets you apply all three in order as a single operation. That composability is where real modularity comes from.
The Template Editor
The template editor in Catalyst Center (Design > Network Profiles > CLI Templates) is functional for day-to-day work. It provides syntax highlighting for both Velocity and Jinja2 (the two scripting languages Catalyst Center supports), inline variable detection, a built-in simulator that lets you fill in variable values and preview the rendered output before pushing anything to a device, and a version control system that tracks every committed change with a history and diff view. The version control is worth understanding: saving a template stages it, while committing creates a new version in the history. This works conceptually like Git, but it is entirely internal to Catalyst Center. If you want to keep templates in external version control (which you should, and we will cover that), you need to export them manually.
Velocity and Jinja2: What You Need to Know
Catalyst Center supports two template scripting languages: Apache Velocity and Jinja2. Velocity has been in Catalyst Center (originally DNA Center) for longer and you will see it in most existing template libraries. Jinja2 is the newer option and has a cleaner, more Pythonic syntax that most network engineers find easier to read and write. If you are starting a new template library, Jinja2 is the better choice. If you are inheriting an existing Velocity template library, it still works and there is no urgent reason to rewrite everything.
Both languages support the same core capabilities: variable substitution, conditional logic, and loops. Here is what each looks like in practice:
Velocity Syntax
## Set NTP servers based on site region
#if($site_region == "east")
ntp server 10.1.0.1 prefer
ntp server 10.1.0.2
#elseif($site_region == "west")
ntp server 10.2.0.1 prefer
ntp server 10.2.0.2
#else
ntp server 10.0.0.1 prefer
#end
## Configure management interface
interface Vlan$mgmt_vlan
description Management
ip address $mgmt_ip $mgmt_mask
no shutdownJinja2 Syntax
{# Set NTP servers based on site region #}
{% if site_region == "east" %}
ntp server 10.1.0.1 prefer
ntp server 10.1.0.2
{% elif site_region == "west" %}
ntp server 10.2.0.1 prefer
ntp server 10.2.0.2
{% else %}
ntp server 10.0.0.1 prefer
{% endif %}
{# Configure management interface #}
interface Vlan{{ mgmt_vlan }}
description Management
ip address {{ mgmt_ip }} {{ mgmt_mask }}
no shutdownThe logic is identical. Jinja2 uses {% %} for control statements and {{ }} for variable output. Velocity uses # for directives and $ for variables. Pick one and be consistent across your library.
Variable Types
Catalyst Center exposes three categories of variables in templates:
- Binding variables are values you provide at provisioning time through the UI or API. These are the inputs the engineer fills in: hostname, management IP, VLAN ID, site code, etc. These are what make a template reusable across devices with different values.
- System variables are values Catalyst Center generates automatically from its inventory. Device platform, serial number, current software version, and similar data are available as system variables. You can use them in templates without the operator having to type anything.
- Regular variables are values you define within the template itself, typically to hold intermediate results or constants that are used across multiple places in the same template.
The binding variables are where most of the design work goes. Getting variable naming and data types right at the start saves significant pain later (more on that in the pitfalls section).
The Practical Value: Why Templates Beat Manual Config
The argument for templates is not that they are faster than typing CLI (for a single device, they often are not). The argument is that they are consistent, auditable, and repeatable across dozens or hundreds of devices.
A well-written Day 0 template means every switch that comes out of the box gets the same baseline configuration: same AAA server group, same NTP servers, same SNMP community strings and ACLs, same SSH version and key size, same logging configuration. When a security team audits your network, compliance is a matter of checking which template was applied, not reading running configs on 300 switches one at a time.
A well-written Day N template for VLAN provisioning means that adding a VLAN to a group of access switches is a form submission, not a change window with CLI commands on each device. It also means the VLAN addition produces the same configuration on every switch, which matters when you are troubleshooting a connectivity issue at 11pm and need to know whether the configuration is right.
The human error reduction is the most immediately valuable thing. Templates do not typo IP addresses. Templates do not forget to configure the switchport access vlan command after configuring the interface description. Templates apply the same eight lines of AAA config to device 1 as they do to device 150.
How to Structure Templates Well
The biggest structural decision is scope: what belongs in a single template versus what should be broken into multiple templates and composed. The right answer is smaller, focused templates rather than large monolithic ones.
Modular Design
Think of your template library in functional layers. A reasonable structure for a campus environment looks like this:
- Base infrastructure template: Hostname convention, domain name, DNS, NTP, logging, SNMP, SSH configuration, AAA (TACACS+/RADIUS server groups, authentication/authorization/accounting method lists). This applies to every managed device, every time.
- Role-specific templates: Access layer gets spanning-tree portfast default, storm-control defaults, port security policies. Distribution layer gets HSRP/VRRP configuration, IP routing, inter-VLAN routing policy. Each role has its own template.
- Site-specific templates: Site code, building designation, any parameters that vary by physical location but not by device role (local syslog forwarder, local DHCP server, etc.).
- Change templates: Operational Day N templates for specific changes: VLAN provisioning, interface configuration, ACL updates. These are applied on demand, not tied to onboarding.
A composite template for new switch onboarding would sequence: base infrastructure, then role-specific, then site-specific. That is three small, testable templates rather than one 200-line monster. When the AAA server address changes, you update one template and every device type benefits.
Variable Naming and Design
Variable design is where the quality of your template library gets decided. Sloppy variable design creates templates that are painful to use, hard to automate via API, and difficult to validate before applying. A few principles that save headaches:
- Use descriptive, consistent names.
mgmt_vlan_idis better thanvlan.ntp_server_primaryis better thanntp1. When you are filling in values for 20 templates six months from now, clarity in variable names prevents mistakes. - Enforce data types where possible. Catalyst Center lets you define variable types (string, integer, IP address, boolean). Use integer for VLAN IDs so that the system validates the input before the template runs. Use IP address type for addresses so that typos fail at input time, not at push time.
- Set default values for optional parameters. If most devices use the same logging server but a handful are exceptions, set the default in the template and let operators override it when needed. This keeps the provisioning form short and reduces the chance of missing a required field.
- Avoid deeply nested conditional logic. If your template has conditionals three levels deep, you have a maintenance problem. Break it into separate templates by role or environment instead.
Designing for Idempotency
An idempotent template is one that produces the same result whether you run it once or five times. IOS-XE helps here because most configuration commands are additive (running the same ntp server command twice does not create two entries), but edge cases exist. Be careful with anything that has a numbered sequence (access lists, route maps) or that uses no commands internally. If your template issues a no interface Vlan10 followed by a reconfiguration block, applying it twice on a live device can cause a brief outage the second time. Test this explicitly with the built-in simulator and, where possible, on a lab device before putting a template into production rotation.
Common Pitfalls
Template Sprawl
Template sprawl is the most common long-term problem. It starts innocently: someone needs a slightly different version of the VLAN template for one site, so they copy it and modify it. Someone else needs a version with a different ACL, so they copy that one. Six months later you have eleven VLAN templates, nobody remembers which one is authoritative, and a change to VLAN provisioning logic requires updating eleven files or guessing which ones matter.
The mitigation is discipline, not tooling. Establish a naming convention and a review process before you have more than a handful of templates. Require that changes to existing templates go through a review step (even if the review is just a second engineer looking at it). Prefer variables over copies: if two use cases are 90% the same, the right answer is usually a single template with a conditional block, not two separate templates.
No External Version Control
Catalyst Center's internal version history is useful for auditing, but it is not a substitute for an external repository. Catalyst Center does not give you branching, pull requests, or the ability to roll back the entire template library to a point in time. Export your templates to a Git repository on a regular basis. Even a simple process (export to JSON, commit, push to a shared repo once a month) is dramatically better than relying entirely on Catalyst Center's internal versioning, which disappears if you ever need to rebuild or migrate your Catalyst Center instance.
Velocity and Jinja2 Fragility
The template scripting languages are where most technical fragility lives. A few specific patterns that cause problems in production:
- Whitespace sensitivity in Jinja2: Jinja2 is sensitive to leading and trailing whitespace in ways that are not obvious until you see unexpected blank lines in rendered output. Use
{%- -%}(with dashes) to strip whitespace around control blocks when it matters for IOS syntax. - Null variable handling: If a binding variable is left empty and your template does not handle that case, the rendered output will contain the literal variable name or throw an error depending on the engine version. Add null checks for any variable that is not required: in Jinja2,
{% if variable is defined and variable %}; in Velocity,#if($variable). - Platform-specific IOS syntax: A template written for IOS-XE 16.x may not render correctly on IOS 15.x or on a switch running a significantly different software generation. Platform-conditional logic adds complexity, but it beats applying a template to a mixed fleet and finding out later that half the devices accepted it and half silently failed.
Version Lock
Templates that encode platform-specific or software-version-specific assumptions become a burden when your fleet evolves. If your base template references a feature that was introduced in a specific IOS-XE release, applying it to older devices either fails or produces a device in an inconsistent state. Document the minimum software version assumption for each template in a comment block at the top. When you upgrade your fleet, validate templates against the new version before using them in production. This sounds obvious and is regularly skipped.
Lack of Testing Discipline
The built-in simulator shows you the rendered output (what the CLI will look like after variable substitution) but does not validate whether that CLI is syntactically correct or will be accepted by a device. The only way to know that is to test on real hardware (or a CML lab, if you have one). Establish a practice of testing every new template and every significant change on a non-production device before rolling it to the fleet. This seems slow in the moment and prevents the category of incident where you push a template to 50 switches at 2am and discover the rendered config has a typo in a critical ACL entry.
A Practical Adoption Path for Teams Starting from Zero
If your team is starting from fully manual operations, the fastest path to value without creating new problems is incremental adoption. Do not try to template everything at once.
| Phase | What to build | Why to start here |
|---|---|---|
| Phase 1: Baseline | A single Day 0 onboarding template covering AAA, NTP, SNMP, SSH, logging | Highest consistency value, lowest risk. Every new device benefits immediately. Template is stable and changes infrequently. |
| Phase 2: VLAN operations | A Day N VLAN provisioning template (create VLAN, assign to interfaces, update trunk allowances) | VLAN additions are a frequent, repetitive task. Templating this one workflow delivers visible time savings and reduces the most common config drift vector. |
| Phase 3: Role differentiation | Separate access and distribution templates; introduce composite templates | Once baseline and VLAN templates are stable and trusted, role-specific templates add value without much additional complexity. |
| Phase 4: Change automation | Templates for common Day N changes: ACL updates, interface reconfigurations, QoS policy | Build this library based on what your team actually does repeatedly, not based on what seems theoretically useful. One well-used template is worth ten unused ones. |
At each phase, the goal is a small library of templates that the whole team understands and trusts, not a comprehensive library that nobody maintains. Get comfortable with the tool, establish the governance habits (naming, review, external version control), and add templates as operational demand justifies them.
One practical note on starting from scratch: before writing your first template, spend time in the simulator with a device that already has a known-good configuration. Export its running config and use that as your template source. Templating a configuration you have already validated in production is faster and safer than writing from scratch.
When Templates Are Enough and When to Graduate
CLI templates in Catalyst Center have a real ceiling. Understanding where that ceiling is helps you decide when to keep using them and when a different tool is the right answer.
| Use case | Templates: enough? | Notes |
|---|---|---|
| Day 0 device onboarding | Yes | This is the core use case. Templates with PnP are well-suited to this workflow. |
| Repeatable Day N config changes (VLAN, ACL, interface) | Yes | Exactly what templates are designed for. |
| Site-wide rollout of a config change | Yes | Catalyst Center can apply a template to a device group. This scales well for common changes. |
| Complex conditional logic based on live device state | No | Templates cannot query the device or make decisions based on current running state. Ansible or Python with a library like Netmiko handles this better. |
| Stateful operations (e.g., orchestrated failover, traffic engineering) | No | Templates push config; they do not coordinate multi-device state machines. |
| Integration with external data sources (IPAM, CMDB, ticketing) | Partially | You can call the Catalyst Center API to trigger template deployment with variables pulled from an external system, but the integration code lives outside Catalyst Center. |
| Cross-platform automation (Cisco + Aruba + Juniper) | No | Templates are Catalyst Center and Cisco IOS-XE specific. Multi-vendor environments need Ansible, Nornir, or similar. |
| Config drift detection and remediation | Partially | Catalyst Center has compliance checks, but complex drift detection and automated remediation at scale is better served by a dedicated tool. |
The graduation trigger is usually stateful complexity or cross-platform scope. If you are adding a VLAN to 80 campus switches, a Catalyst Center template applied to a device group is fast, auditable, and does not require you to maintain a Python environment. If you are implementing a configuration workflow that needs to read the current state of a device, make a decision based on that state, and then push a different configuration depending on what it finds, you need a proper automation tool. Ansible playbooks, Python with NAPALM or Netmiko, or Cisco's own NSO are appropriate at that point.
The right framing is not "templates or automation frameworks." It is "use templates for what templates do well, and graduate to more powerful tooling when the workflow actually requires it." Many teams that graduate to Ansible still keep their Catalyst Center template library for Day 0 onboarding because the PnP workflow integrates naturally with the template system and does not need the additional complexity of Ansible for that use case.
Key Takeaways
- CLI templates in Catalyst Center are a pragmatic middle ground between fully manual operations and a full automation framework. They are well-suited to teams with moderate scripting maturity who need consistency without operational overhead.
- Day 0 templates handle onboarding via PnP; Day N templates handle ongoing provisioning. Composite templates sequence multiple regular templates into a single operation.
- Catalyst Center supports both Velocity and Jinja2. For new template libraries, Jinja2 is the better choice. Consistency within your library matters more than which language you pick.
- Invest time in variable design upfront. Descriptive names, enforced data types, and sensible defaults make templates easier to use and reduce errors at provisioning time.
- Template sprawl is the biggest long-term risk. A small library of well-maintained, well-tested templates is far more valuable than a large library of inconsistent, untrusted ones.
- Export templates to an external Git repository. Catalyst Center's internal versioning is not a substitute for source control you own.
- Templates do not handle stateful operations, complex conditional logic based on live device state, or cross-vendor environments. When your requirements outgrow these limits, that is the right time to look at Ansible, Python, or NSO, not before.