NetStacksNetStacks

Template Versioning

TeamsEnterprise

How NetStacks tracks every template change with immutable versions, and how to compare, diff, and roll back template versions.

Overview

Every edit to a template in NetStacks creates a new, immutable version. The template object tracks a current_version number that increments with each save. Previous versions are never deleted or overwritten — they form a complete audit trail of how the configuration evolved over time.

Versioning provides three key capabilities:

  • History — See every version of the template with who created it and when
  • Comparison — Diff any two versions side by side to see exactly what changed
  • Rollback — Restore a previous version by copying its source into a new version, preserving the full history

This is especially important for network configurations where a small change can cause outages. Version history lets you trace issues back to the exact config change that caused them and quickly revert.

How It Works

The versioning model is built on two data structures from the Stacks plugin:

JinjaTemplate

The template object stores the current state including the current_version number, the latest template_source, and the list of extracted variables.

JinjaTemplateVersion

Each version is stored as a separate record containing:

  • version — Integer version number (1, 2, 3, ...)
  • template_source — The complete template content at that version
  • created_by — The user ID who created the version
  • created_at — Timestamp when the version was created

Version Creation

When you update a template via PUT to /plugins/stacks/admin/templates/:id with a modified template_source, NetStacks:

  1. Creates a new JinjaTemplateVersion with the updated source
  2. Increments the current_version number on the template
  3. Re-extracts variables from the new source
  4. Updates the template's updated_at timestamp

Versions are immutable once created. You cannot edit a historical version — you can only create new versions.

Retrieving Version History

To fetch the full version history, use the ?include_versions=true query parameter on the GET template endpoint. Without this parameter, only the current template state is returned.

Step-by-Step Guide

Step 1: Edit a Template and Save

Open an existing template in the editor, make your changes, and click Save. NetStacks automatically creates a new version with the updated content. The version number increments from the previous value.

Step 2: View Version History

Open the template and navigate to the version history panel. You will see a chronological list of all versions with the version number, author, and timestamp.

Step 3: Compare Two Versions

Select any two versions to see a side-by-side diff. Lines added in the newer version are highlighted in green, removed lines in red. This makes it easy to identify exactly what changed between any two points in the template's history.

Step 4: Roll Back to a Previous Version

To revert to a previous version, select the version you want to restore and click Restore This Version. This copies the historical version's template source into a new version (incrementing the version number), so the full history is preserved. Rolling back does not delete any versions.

Rollback and Active Stacks

Rolling back a template does not automatically re-deploy to devices that are currently running a configuration from a newer version. You will need to trigger a new deployment on affected stack instances after rolling back.

Step 5: Verify the Rollback

After restoring, preview the template with test variables to confirm the output matches what you expect. Then check any stack instances using this template to decide whether re-deployment is needed.

Code Examples

Retrieve Template with Version History

get-template-versions.shbash
GET /plugins/stacks/admin/templates/tmpl_8f3a2b1c?include_versions=true
Authorization: Bearer <token>

Response with Version History

template-with-versions.jsonjson
{
  "id": "tmpl_8f3a2b1c",
  "name": "interface-l3-ios",
  "description": "Layer 3 interface configuration for Cisco IOS",
  "template_source": "interface {{ interface_name }}\n description {{ description }}\n ip address {{ ip_address }} {{ subnet_mask }}\n ip ospf {{ ospf_process_id }} area {{ ospf_area }}\n no shutdown",
  "current_version": 3,
  "variables": ["interface_name", "description", "ip_address", "subnet_mask", "ospf_process_id", "ospf_area"],
  "owner_id": "usr_a1b2c3d4",
  "created_at": "2025-08-15T09:30:00Z",
  "updated_at": "2025-09-02T14:15:00Z",
  "versions": [
    {
      "version": 1,
      "template_source": "interface {{ interface_name }}\n description {{ description }}\n ip address {{ ip_address }} {{ subnet_mask }}\n no shutdown",
      "created_by": "usr_a1b2c3d4",
      "created_at": "2025-08-15T09:30:00Z"
    },
    {
      "version": 2,
      "template_source": "interface {{ interface_name }}\n description {{ description }}\n ip address {{ ip_address }} {{ subnet_mask }}\n no ip proxy-arp\n no shutdown",
      "created_by": "usr_a1b2c3d4",
      "created_at": "2025-08-22T11:00:00Z"
    },
    {
      "version": 3,
      "template_source": "interface {{ interface_name }}\n description {{ description }}\n ip address {{ ip_address }} {{ subnet_mask }}\n ip ospf {{ ospf_process_id }} area {{ ospf_area }}\n no shutdown",
      "created_by": "usr_e5f6g7h8",
      "created_at": "2025-09-02T14:15:00Z"
    }
  ]
}

Version Diff Example

Comparing version 1 to version 3 of the template above shows the following changes:

version-diff-v1-v3.difftext
  interface {{ interface_name }}
   description {{ description }}
   ip address {{ ip_address }} {{ subnet_mask }}
+  ip ospf {{ ospf_process_id }} area {{ ospf_area }}
   no shutdown

Version 2 added no ip proxy-arp (later removed in version 3), and version 3 added OSPF interface configuration. The diff between version 1 and 3 shows only the net change.

Update Template (Creates New Version)

update-template.shbash
PUT /plugins/stacks/admin/templates/tmpl_8f3a2b1c
Content-Type: application/json
Authorization: Bearer <token>

{
  "template_source": "interface {{ interface_name }}\n description {{ description }}\n ip address {{ ip_address }} {{ subnet_mask }}\n ip ospf {{ ospf_process_id }} area {{ ospf_area }}\n ip ospf cost {{ ospf_cost | default(10) }}\n no shutdown"
}

This creates version 4 with the added OSPF cost line.

Questions & Answers

Q: Are template versions created automatically?
A: Yes. Every time you save changes to a template (via the UI or the PUT API endpoint), a new version is created automatically. The version number increments sequentially and the previous version's content is preserved as an immutable record.
Q: Can I delete old versions?
A: No. Versions are immutable and cannot be deleted. This is by design — the complete version history serves as an audit trail for compliance and troubleshooting. If a template is no longer needed at all, you can delete the entire template, which removes all versions.
Q: How do I compare two versions?
A: Fetch the template with ?include_versions=true to get all versions. In the UI, select any two versions to see a side-by-side diff. The diff highlights added lines (green) and removed lines (red) between the two selected versions.
Q: How do I roll back to a previous version?
A: Select the version you want to restore and click "Restore This Version." This creates a new version (with the next version number) whose content matches the historical version. Rolling back never deletes intermediate versions — the full history is always preserved.
Q: Does rolling back affect deployed stacks?
A: Rolling back the template does not automatically re-deploy to devices. Any stack instances using this template will continue running the configuration they were last deployed with. To push the rolled-back version to devices, you need to trigger a new deployment on the affected stack instances.
Q: Can I see who made each version?
A: Yes. Each JinjaTemplateVersion record includes a created_by field with the user ID of the person who saved that version, along with a created_at timestamp.

Troubleshooting

Version history not appearing

Make sure you are requesting the template with the ?include_versions=true query parameter. Without this parameter, the API returns only the current template state and omits the versions array to reduce payload size.

Unexpected version numbering after rollback

Rolling back creates a new version with the next sequential number. For example, if you roll back from version 5 to version 2, the restored content becomes version 6. The version number always increments — it never reuses or resets previous numbers.

Concurrent edits creating unexpected versions

If two team members edit the same template simultaneously, both saves will create new versions. The second save becomes the current version and may overwrite the first person's changes in the active version. Review the version history to see both sets of changes and manually merge if needed.

No Merge Conflict Detection

NetStacks does not currently detect or merge conflicting edits. If multiple people edit the same template, the last save wins as the current version. Use version history to recover any overwritten changes.

Rollback did not change deployed devices

Rolling back a template only changes the template source. It does not automatically push the change to devices. After rolling back, navigate to the stack instances using this template and trigger a re-deployment to update device configurations.

Related documentation for template versioning and deployment workflows:

  • Template Basics — Introduction to templates and the authoring lifecycle
  • Rendering & Preview — Preview rendered output after editing or rolling back a template
  • Deployment History — Track which template version was deployed to each device and when
  • Stack Instances — Manage deployments and trigger re-deployment after template changes