Template Basics
TeamsEnterpriseIntroduction to configuration templates in NetStacks -- what they are, how to create one, and when to use them for network config management.
Overview
Configuration templates are the foundation of NetStacks' config management workflow. A template is a Jinja2-based document that defines device configuration as reusable, parameterized code. Instead of manually typing the same interface descriptions, SNMP communities, and NTP servers across hundreds of switches, you write the configuration once with variable placeholders and let NetStacks fill in device-specific values at deployment time.
Templates solve several problems that network engineers face daily:
- Consistency — Every device gets the same baseline configuration structure, eliminating drift caused by manual edits
- Speed — Deploy standardized configs to dozens or hundreds of devices in a single operation instead of one at a time
- Auditability — Every template change is versioned, so you can see who changed what and when
- Safety — Preview rendered output and diff it against the running config before pushing anything to production
Templates are part of the Stacks plugin. A template on its own defines configuration logic. When you attach templates to a Stack, you get a complete deployment workflow with target devices, variable values, and deployment history.
How It Works
The template lifecycle follows a straightforward path from authoring to deployment:
- Author — Write configuration using Jinja2 syntax with{{ variable }} placeholders for device-specific values
- Extract — NetStacks automatically parses your template source and discovers all variable names from {{ }} expressions
- Version — Every save creates a new version. The template tracks a
current_versionnumber and stores the full history of previous versions - Render — Combine the template with variable values to produce final device configuration. Preview output before deployment
- Deploy — Push rendered configuration to target devices through a Stack instance, with rollback support if something goes wrong
Templates are stored as JinjaTemplate objects with a name, description, the raw template source, a list of extracted variable names, and version metadata. The Jinja2 rendering engine runs in a sandboxed environment — templates cannot access the file system, make network calls, or import arbitrary code. This makes it safe to run templates authored by any team member.
Template rendering is sandboxed for security. Templates can use built-in Jinja2 filters and control structures but cannot execute arbitrary code, read files, or make network requests.
Step-by-Step Guide
Follow these steps to create your first configuration template.
Step 1: Navigate to the Templates Section
In the NetStacks Terminal, open the Stacks plugin from the sidebar and select the Templates tab. This shows all templates in your organization.
Step 2: Create a New Template
Click New Template. Enter a descriptive name and an optional description. Use a naming convention that identifies the configuration type and target platform, such as snmp-config-ios or bgp-neighbor-nxos.
Use a consistent naming pattern like <purpose>-<platform>. Examples: snmp-config-ios, vlan-setup-nxos, ospf-area-junos. This makes templates easy to find and filter.
Step 3: Write the Template Content
Use Jinja2 syntax to write your configuration. Place variable placeholders where device-specific values belong:
hostname {{ hostname }}
!
snmp-server community {{ snmp_community }} RO
snmp-server location {{ location }}
snmp-server contact {{ contact }}Step 4: Review Extracted Variables
After entering your template content, NetStacks automatically extracts variable names from {{ }} expressions. You will see the list of discovered variables — in this case: hostname, snmp_community, location, and contact.
Step 5: Save the Template
Click Save. NetStacks creates the template at version 1. Every subsequent edit will increment the version number, and you can always view or restore previous versions.
Step 6: Test with Preview
Before deploying, use the render/preview feature to see the final output with sample variable values. This confirms your template produces valid configuration.
Code Examples
SNMP Configuration Template
A basic SNMP template for Cisco IOS devices with community strings, location, contact, and trap host configuration:
{# SNMP Configuration - Cisco IOS #}
{# Variables: snmp_community, snmp_rw_community, location, contact, trap_hosts #}
snmp-server community {{ snmp_community }} RO
{% if snmp_rw_community is defined and snmp_rw_community %}
snmp-server community {{ snmp_rw_community }} RW
{% endif %}
snmp-server location {{ location | default('DC1 Row-A Rack-12') }}
snmp-server contact {{ contact | default('noc@example.com') }}
snmp-server enable traps
{% for host in trap_hosts %}
snmp-server host {{ host }} version 2c {{ snmp_community }}
{% endfor %}Interface Configuration Template
A Layer 3 interface template with IP addressing, description, and optional HSRP:
{# Layer 3 Interface Configuration - Cisco IOS #}
{# Variables: interface_name, ip_address, subnet_mask, description, hsrp_enabled, hsrp_vip, hsrp_priority #}
interface {{ interface_name }}
description {{ description }}
ip address {{ ip_address }} {{ subnet_mask }}
no ip proxy-arp
{% if hsrp_enabled | default(false) %}
standby 1 ip {{ hsrp_vip }}
standby 1 priority {{ hsrp_priority | default(100) }}
standby 1 preempt
{% endif %}
no shutdownNTP Server Configuration Template
An NTP configuration template that supports multiple NTP servers with a preferred server and source interface:
{# NTP Configuration - Cisco IOS #}
{# Variables: ntp_servers, source_interface #}
{% for server in ntp_servers %}
ntp server {{ server }}{% if loop.first %} prefer{% endif %}
{% endfor %}
ntp source {{ source_interface | default('Loopback0') }}
ntp authenticate
ntp trusted-key 1
ntp authentication-key 1 md5 {{ ntp_auth_key | default('NtpSecure!') }}Questions & Answers
- Q: What are configuration templates in NetStacks?
- A: Templates are Jinja2-based documents that define device configuration as reusable, parameterized code. You write the configuration structure once with variable placeholders like {{ hostname }} and {{ ip_address }}, then render the template with device-specific values to produce final configuration output. Templates are stored, versioned, and managed through the Stacks plugin.
- Q: What templating language does NetStacks use?
- A: NetStacks uses Jinja2, a widely adopted templating language from the Python ecosystem. Jinja2 provides variable substitution ({{ }}), control structures like conditionals ({% if %}) and loops ({% for %}), filters for transforming output, and macros for reusable blocks. If you have used Ansible templates, the syntax is identical.
- Q: How are variables defined in a template?
- A: You do not need to declare variables separately. Simply use {{ variable_name }} anywhere in your template source. When you save the template, NetStacks automatically parses the Jinja2 expressions and extracts a list of all variable names. These appear in the
variablesarray on the template object. - Q: Can I use the same template for different device types?
- A: Yes. You can use Jinja2 conditionals to branch on a device type variable. For example, {% if platform == 'cisco_ios' %} produces IOS-style commands while {% elif platform == 'juniper_junos' %} produces JunOS set commands. Alternatively, create separate templates per platform and attach the appropriate one to each stack.
- Q: Are templates versioned automatically?
- A: Yes. Every time you save changes to a template, NetStacks creates a new version with an incremented version number. The template stores the current version number and you can retrieve the full version history to compare changes, view diffs, or roll back to a previous version.
- Q: What happens if I reference a variable that has no value at render time?
- A: Jinja2 will raise an undefined variable error by default. You can guard against this by using the
defaultfilter: {{ contact | default('noc@example.com') }}. For optional blocks, wrap them in {% if variable is defined %} conditionals.
Troubleshooting
Template syntax errors on save
If the template fails to save, check for unclosed Jinja2 tags. Every {% if %} needs a matching {% endif %}, and every {% for %} needs a matching {% endfor %}. Use the validation endpoint to get detailed error messages with line numbers:
POST /plugins/stacks/admin/templates/validate
Content-Type: application/json
{
"template_source": "{% if enable_snmp %}\nsnmp-server community {{ community }} RO"
}
# Response (error):
{
"valid": false,
"error": "Unexpected end of template. Expected 'endif' at line 2."
}Variables not being extracted
If your variables do not appear in the extracted list, verify that you are using double curly braces: {{ variable_name }}. Single braces like { variable_name } are not Jinja2 syntax. Also check that variable names use only letters, numbers, and underscores — names like {{ my-variable }} with hyphens are not valid Python identifiers.
Template will not save — required fields missing
Every template requires a name and template_source. The description field is optional. If the save button is disabled, check that you have entered a template name and that the template content is not empty.
Rendered output looks incorrect
Use the preview feature to render your template with test values. If the output has extra blank lines, use Jinja2 whitespace control: {%- if ... -%} strips whitespace around the tag. See the Jinja2 Syntax page for details.
Related Features
Continue learning about the template workflow with these related pages:
- Jinja2 Syntax — Full reference for filters, conditionals, loops, macros, and template inheritance
- Variables & Extraction — How variables are discovered, typed, and populated from multiple sources
- Template Versioning — View version history, compare diffs, and roll back changes
- Rendering & Preview — Preview rendered output and validate syntax before deployment
- Example Templates — Real-world templates for VLAN, ACL, BGP, OSPF, and interface configs
- Stack Templates — Combine templates into deployment stacks with target devices and variables