Variable Overrides
TeamsEnterpriseCustomize stack variable values per device using the override precedence chain to tailor deployments for individual devices.
Overview
When deploying a stack to multiple devices, most variable values are the same across all targets — the NTP server, SNMP community, and syslog destination are typically identical for every device in a site. But some values must be unique per device: hostnames, management IPs, interface descriptions, and physical locations.
Device overrides let you customize specific variable values for individual target devices without changing the shared defaults. The device_overrides field on a stack instance is a nested map keyed by device ID, where each entry contains variable-value pairs that apply only to that device.
Use per-device variables (declared in the stack template) when a variable always differs per device (like hostname). Use device overrides when a normally-shared variable needs a different value on specific devices (for example, a different NTP server for a device on an isolated management network).
How It Works
Variable Precedence Chain
When NetStacks renders a template for a specific device, it resolves each variable using a three-level precedence chain (highest priority wins):
- Per-device override (highest priority) — A value set in
device_overrides[device_id][variable_name]. If present, this value is used regardless of other levels. - Shared instance value — A value set in the stack instance's
variable_valuesmap. Applies to all devices unless overridden. - Template default (lowest priority) — A default value defined in the Jinja2 template using the
default()filter (for example,{{ timezone | default('UTC') }}).
Merge Behavior at Render Time
For each target device, NetStacks creates a merged variable context by starting with template defaults, layering on shared instance values, and then applying any device-specific overrides. The merged context is passed to the Jinja2 renderer to produce the final configuration for that device.
Override Storage Structure
The device_overrides field is stored as a Record<string, Record<string, any>> where the outer key is the device ID and the inner map contains variable name-value pairs. Only variables that differ from the shared values need to be listed in the override.
Step-by-Step Guide
Walk through configuring per-device overrides for a three-switch deployment where each switch needs a unique hostname, management IP, and rack location.
Step 1: Fill Shared Variables During Instance Creation
When creating the stack instance, provide values for variables shared across all devices. These become the baseline values:
ntp_server:10.0.0.10snmp_community:netstack$ROsyslog_server:10.0.0.20timezone:America/New_York
Step 2: Add Device-Specific Overrides
For each target device, expand the device entry and set override values for variables that differ:
- access-sw-01: hostname =
access-sw-01.nyc, management_ip =10.1.1.1, snmp_location =NYC-Floor3-Rack1 - access-sw-02: hostname =
access-sw-02.nyc, management_ip =10.1.1.2, snmp_location =NYC-Floor3-Rack4 - access-sw-03: hostname =
access-sw-03.nyc, management_ip =10.1.1.3, snmp_location =NYC-Floor4-Rack2
Step 3: Preview Rendered Output
Before deploying, use dry-run mode to preview the rendered configuration for each device. Verify that shared values are consistent and overrides produce the expected device-specific output.
You do not need to repeat shared values in device overrides. Only specify variables whose values differ from the shared defaults. For example, if all switches use the same NTP server, do not include ntp_server in overrides.
Step 4: Deploy and Verify
Deploy the stack instance. After deployment completes, inspect the rendered config for each device to confirm that overrides were applied correctly.
Step 5: Modify Overrides After Deployment
If you need to change an override value after the initial deployment, use the Modify action. Update the variable value for the specific device, then Redeploy to push the change.
Code Examples
Device Overrides Structure
This example shows three access switches sharing NTP and SNMP settings with device-specific hostnames, IPs, and rack locations:
{
"variable_values": {
"ntp_server": "10.0.0.10",
"snmp_community": "netstack$RO",
"syslog_server": "10.0.0.20",
"timezone": "America/New_York"
},
"device_overrides": {
"dev-sw-001": {
"hostname": "access-sw-01.nyc",
"management_ip": "10.1.1.1",
"snmp_location": "NYC-Floor3-Rack1"
},
"dev-sw-002": {
"hostname": "access-sw-02.nyc",
"management_ip": "10.1.1.2",
"snmp_location": "NYC-Floor3-Rack4"
},
"dev-sw-003": {
"hostname": "access-sw-03.nyc",
"management_ip": "10.1.1.3",
"snmp_location": "NYC-Floor4-Rack2"
}
}
}Rendered Output Comparison
Given an SNMP template, here is how the rendered output differs between two devices based on their overrides:
! Rendered for access-sw-01 (dev-sw-001)
hostname access-sw-01.nyc
snmp-server community netstack$RO RO
snmp-server location NYC-Floor3-Rack1
snmp-server host 10.0.0.20
ntp server 10.0.0.10! Rendered for access-sw-02 (dev-sw-002)
hostname access-sw-02.nyc
snmp-server community netstack$RO RO
snmp-server location NYC-Floor3-Rack4
snmp-server host 10.0.0.20
ntp server 10.0.0.10Modify Overrides After Deployment
Change the SNMP location for a single device after the stack has been deployed:
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
"https://controller.example.net/plugins/stacks/admin/deployments/modify" \
-d '{
"stack_instance_id": "inst-a7c4e2d1",
"device_overrides": {
"dev-sw-001": {
"hostname": "access-sw-01.nyc",
"management_ip": "10.1.1.1",
"snmp_location": "NYC-Floor3-Rack2-Moved"
}
}
}'Questions & Answers
- Q: What are variable overrides?
- A: Variable overrides are per-device customizations of variable values in a stack instance. They allow you to set different values for specific devices while keeping shared defaults for all other devices. Overrides are stored in the
device_overridesfield, keyed by device ID. - Q: What is the precedence order for variable resolution?
- A: Variables are resolved in this order (highest priority first): (1) per-device override, (2) shared instance value, (3) Jinja2 template default. If a variable has a device override, that value is used. Otherwise, the shared instance value is used. If neither exists, the template's
default()filter value is used. - Q: Can I override shared variables per device?
- A: Yes. Any variable — whether classified as shared or per-device in the stack template — can be overridden for a specific device. For example, if one device uses a different NTP server than the rest (a shared variable), you can set
ntp_serverin that device's override without changing it for other devices. - Q: How do I modify overrides after deployment?
- A: Use the
modifyAPI endpoint with the updateddevice_overridesmap. Then trigger aredeployto push the updated configuration to the affected devices. The modify action updates the stored variable values without re-creating the instance. - Q: What happens if an override references a non-existent variable?
- A: If you set an override for a variable name that does not exist in any of the stack's Jinja2 templates, the override is stored but has no effect on rendered output. The Jinja2 renderer only uses variables that appear in template expressions. No error is raised, but the value is silently unused.
- Q: Can I remove an override after setting it?
- A: Yes. Use the modify action and omit the variable from the device's override map. The variable will fall back to its shared instance value or template default on the next deployment.
Troubleshooting
Override not applied to device
If a device's rendered configuration does not reflect your override, verify that the device ID in the device_overrides map exactly matches the device_id in the target_devices list. Device IDs are case-sensitive. A mismatched ID means the override is stored but never matched to a target device.
Unexpected rendered output
If the rendered config shows an unexpected value, check the precedence chain. A device override takes priority over shared values, which take priority over template defaults. Use dry-run mode to preview rendered output for each device and trace which level each variable value comes from.
Typo in override variable name
If you misspell a variable name in a device override (for example, hostnme instead of hostname), the Jinja2 renderer will not find a match and the override has no effect. The correctly-spelled variable will use the shared value or template default. Double-check variable names against the stack template's variable list.
Override persists after removal
If you removed an override via the modify action but the old value still appears on the device, the change has not been redeployed. Use the Redeploy action to push the updated configuration. Modifying overrides only updates the stored values; it does not automatically push changes to devices.
Related Features
Learn more about related NetStacks features:
- Template Variables — Understand Jinja2 variable extraction, defaults, and filters
- Creating Stacks — Create stack instances with target devices and variable values
- Stack Instances — Deploy, monitor, and manage live stack deployments
- Template Rendering — How Jinja2 templates are rendered with variable contexts
- Stack Templates — Define variable classification (shared vs per-device) in stack blueprints