---
title: Templates
slug: litmusedge/templates
docTags: 
createdAt: 2026-08-26T16:54:41.068Z
---

A Template is a JSON file that captures configuration from a Litmus Edge (LE) system. When you create one, you select which components to include, such as devices, connectors, analytics flows, and Digital Twins models and instances.

A configuration you build and validate on one system has to be repeated at every new site, often by someone who did not build the original. A template turns that work into a file you build once and apply wherever you need it.

::Image[]{src="https://api.archbee.com/api/optimize/SSUUxKZUk9bFTEPNn_6Zo/DVbomBIyN_A3ZZNno6jlm_image.png" size="80" isUploading="false" width="1561" height="836" darkWidth="1561" darkHeight="836" position="flex-start" alt="Template Details in Solution Templates" showCaption="false"}

# LE and LEM templates

Litmus Edge Manager (LEM) also has templates, and they are also JSON files describing Litmus Edge configuration. Although they can include the same components, they are not the same features and are not interchangeable.

Use LEM templates when you are pushing configuration out to a fleet you already manage centrally. Use Litmus Edge Templates when you are building a configuration on one system and moving it to another, or when you need the snapshot and roll back safety net around a change.

|                                    | Litmus Edge  Template                           |  Litmus Edge Manager template                     |
| ---------------------------------- | ----------------------------------------------- | ------------------------------------------------- |
| Created and applied in             | Litmus Edge, on the device itself               | Litmus Edge Manager, against managed edge devices |
| Scope                              | One system                                      | Instance, company, or project                     |
| Parameterized file                 | A single `.json` file with a `parameters` block | A `.zip` package                                  |
| Apply modes                        | Reset & Apply, Merge & Apply, Apply             | Apply                                             |
| Preflight, snapshots, and rollback | Yes                                             | No                                                |

# Why Templates matter

Templates make a working configuration reusable. With them, you can:

- **Deploy a proven solution quickly.** A tested configuration becomes a file you apply in minutes rather than a procedure someone repeats by hand.
- **Keep sites consistent.** Every system built from the same template starts from the same baseline, so differences between sites are deliberate rather than accidental.
- **Adapt one template to many sites.** Parameters let a single template carry values that differ per site, such as a site identifier or a polling interval, so you do not maintain a separate file for each location.
- **Rollback a change.** Every apply captures a snapshot first, so you can return the system to the state it was in before.

Templates are useful to solution architects who design a configuration once and roll it out, commissioning engineers who bring new sites online, and operations teams who need to return to a known configuration after a change.

# Core components

Templates include the following components:

- **Template file.** A JSON document holding metadata and one section per system component. This is the portable artifact you move between systems.
- **Template listing.** The catalog of templates available on a system. You create, import, edit, apply, and delete templates here.
- **Parameters.** Named placeholders a template can define. Each has a data type and a default value, and you supply a value when you apply the template.
- **Snapshots.** Point-in-time captures of the running configuration. A snapshot has the same shape as a template file but contains only concrete values, never parameter placeholders.

# Template file

Every template contains metadata, followed by one section per component.

| Field         | Type   | Notes                                                             |
| ------------- | ------ | ----------------------------------------------------------------- |
| `name`        | string | Template name. Maximum 32 characters.                             |
| `description` | string | Template description. Maximum 256 characters.                     |
| `createdAt`   | string | Timestamp of initial creation.                                    |
| `createdBy`   | string | User who created the template.                                    |
| `updatedAt`   | string | Timestamp of the last update.                                     |
| `updatedBy`   | string | User who last updated the template.                               |
| `fileVersion` | string | Version of this template file, in `major.minor.revision` format.  |
| `version`     | string | Version of the template schema, in `major.minor.revision` format. |

## Version numbers

A template has two version numbers, both written as `major.minor.revision`.

- `version` is the template schema version. Litmus sets it and you cannot edit it. LE checks it on import to confirm it can read the file.
- `fileVersion` is the content version for one template. A new template starts at `1.0.0`, and LE increments the revision when you save an edit. Major and minor are yours to set.

If you edit a template outside LE, update `fileVersion` yourself.

## Canonical key ordering

LE stores template files with a canonical key order applied to every object in the file. Within each object, keys appear in three groups: scalar values first in alphabetical order, then the parameters section, then objects and arrays in alphabetical order. The rule applies recursively to nested objects.

This exists to make templates readable and diff-friendly. Two templates that describe the same configuration produce the same key order, so a comparison shows real differences. LE applies the ordering whenever a template is saved or exported, so you do not have to author files in this order yourself. A file with non-canonical ordering imports without error and is reordered when saved.

# Parameters

A parameter lets one template serve many systems. Instead of writing a site identifier or a polling interval directly into the file, you declare it as a parameter and supply the value when you apply the template.

Parameters are declared in a top-level `parameters` block, keyed by the component they belong to. Use `_global` for parameters shared across components.

```json
    "parameters": {
        "_global": [
            {
                "UniqueName": "globalEnterpriseName",
                "Description": "Name of the enterprise",
                "DataType": "STRING",
                "DefaultValue": "Acme",
                "UserValue": null
            },
            {
                "UniqueName": "globalDebugLogEnabled",
                "Description": "Global setting for debug logging",
                "DataType": "BOOLEAN",
                "DefaultValue": "true",
                "UserValue": null
            },
            {
                "UniqueName": "globalPollingInterval",
                "Description": "A global value for polling interval",
                "DataType": "INTEGER",
                "DefaultValue": "2000",
                "UserValue": null
            }
        ],
        "dtwin": [
            {
                "UniqueName": "dtwinSiteName",
                "Description": "Name of a manufacturing site",
                "DataType": "STRING",
                "DefaultValue": "Toronto",
                "UserValue": null
            }
        ]
    },
```

Wherever the value belongs in the template, a placeholder object stands in its place:

:::CodeblockTabs
Sample usage on debug logs

```json
   "devicehub": {
        "Git": "48f7d67157",
        "Version": "2.26.32",
        "Devs": [
            {
                "Dev": {
                    "aliasTopics": true,
                    "debug": {
                        "__param__": "globalDebugLogEnabled"
                    },
```

Sample usage on Digital Twins

```none
                "staticAttributes": [
                    {
                        "id": "1b316a9f-a786-4112-a90b-456a2b693d84",
                        "instanceId": "00000000-0000-0000-0000-000000000000",
                        "key": "litmus-uns-area",
                        "modelId": "2b326f64-1a89-4d91-89f2-c776492ed8c8",
                        "parentId": "00000000-0000-0000-0000-000000000000",
                        "type": 1,
                        "value": "area"
                    },
                    {
                        "id": "922215cc-9429-4ef1-9154-c851dff309b8",
                        "instanceId": "00000000-0000-0000-0000-000000000000",
                        "key": "litmus-uns-productionunit",
                        "modelId": "2b326f64-1a89-4d91-89f2-c776492ed8c8",
                        "parentId": "00000000-0000-0000-0000-000000000000",
                        "type": 1,
                        "value": "productionunit"
                    },
                    {
                        "id": "a227c495-83fd-4373-9aae-4644d10d6311",
                        "instanceId": "00000000-0000-0000-0000-000000000000",
                        "key": "litmus-uns-enterprise",
                        "modelId": "2b326f64-1a89-4d91-89f2-c776492ed8c8",
                        "parentId": "00000000-0000-0000-0000-000000000000",
                        "type": 1,
                        "value": {
                            "__param__": "globalEnterpriseName"
                        }
                    },
                    {
                        "id": "c0118322-8ee1-4860-b937-fd31bc8948ed",
                        "instanceId": "00000000-0000-0000-0000-000000000000",
                        "key": "litmus-uns-site",
                        "modelId": "2b326f64-1a89-4d91-89f2-c776492ed8c8",
                        "parentId": "00000000-0000-0000-0000-000000000000",
                        "type": 1,
                        "value": {
                            "__param__": "dtwinSiteName"
                        }
                    }
                ]
```
:::

When you apply the template, LE replaces each placeholder with the value you supplied, or with the default if you supplied none, then applies the resulting document. The following data types are supported.

| Data type | Accepts                      | Notes                                                                                           |
| --------- | ---------------------------- | ----------------------------------------------------------------------------------------------- |
| `STRING`  | Any text                     | Used exactly as entered.                                                                        |
| `INTEGER` | `1000`, `-5`                 | A value with a decimal point is rejected.                                                       |
| `FLOAT`   | `1.5`, `0.001`, `2`, `1.2e3` | Uses `.` as the decimal separator regardless of locale. A whole number such as `2` is accepted. |
| `BOOLEAN` | `true`, `false`              | Case-insensitive. Any other value is rejected.                                                  |

Default and user values are stored as text in the file and converted to the declared type when the template is applied. A value that cannot be converted, such as a decimal supplied for an `INTEGER`, is a validation error that blocks the apply until corrected. Invalid parameter names and values are displayed.

Parameter names must be unique within their scope, not across the whole file. When the same name exists in both `_global` and a component scope, the component-scoped parameter takes precedence, in the same way a local variable shadows a global one in a programming language.

# Importing a template

When you import a template file, LE checks it before adding it to the listing. The check runs in two layers, and both happen offline against the file itself.

- **Syntax.** The file must be valid JSON. A malformed file is rejected with an error identifying where parsing failed.
- **Internal references.** LE then confirms that references inside the file resolve to an object defined elsewhere in the same file. For example, a Digital Twins instance must point to a model that the template defines. An analytics processor input must name a processor the template contains.

A broken reference fails the import, and the error identifies the reference by its path and value. A file that passes both layers is added to the listing. Import also checks both version tags. A `version` or `fileVersion` that is not valid `major.minor.revision` format fails with a descriptive error, as does a file whose schema version is newer than your LE build supports.

These checks run against the file alone. Nothing is compared against the target system until preflight.

# Preflight

Preflight is a validation step that runs when you start an apply. It checks that the target system has the connectors and drivers the template needs.

If the checks pass, the apply continues. If any check fails, LE blocks the apply and reports what is missing. LE writes nothing and takes no snapshot, so the system stays exactly as it was.

# Apply modes

Three modes control how a template is applied. **Apply** is the default. To use **Reset & Apply** or **Merge & Apply**, turn on **Advanced Modes** in the *Apply Templates* dialog.

- **Reset & Apply** replaces the configuration of every component the template includes. Anything in those components that the template does not define is removed. Use it when the template is the whole intended configuration.
- **Merge & Apply** combines the template with what is already there. Matching IDs are overwritten, new items are added, and anything the template does not mention is untouched. LE asks you to confirm first, and declining cancels the whole merge rather than only the conflicting items. LE saves the merged result as a new template. Use it when you are adding a solution to a system that already does other work.
- **Apply** leaves the decision to each component, so behavior varies. LE does not capture a snapshot in this mode, so an **Apply** cannot be rolled back. It exists for compatibility with earlier template behavior.

**Merge & Apply** merges against the system's current configuration, not against the template it was last given. If the system has been modified by hand since, those modifications are part of what gets merged.

## What a reset clears

**Reset & Apply**, **Merge & Apply**, and rollback reset each component before they write the new configuration. **Merge & Apply** resets to the merged result of the template and the current configuration.

## Component errors during an apply

When part of a component can't be applied, the error identifies what failed and why:

- **Digital Twins:** LE skips any model it can't restore and applies the rest. The result names each skipped model and gives the reason, for example a model name that contains a space.
- **DeviceHub:** the error names the device, and the tag when a register is at fault. Device names must be unique and can't start or end with a space.

# Snapshots and rollback

A snapshot is the complete running configuration at a moment in time. It covers every component the template system manages.

A snapshot is self-contained, which is what makes rollback dependable. Restoring one writes its values straight to the system, so the rollback works even if the template it came from has since been edited or deleted.

LE captures a snapshot at the start of every **Reset & Apply** an&#x64;**&#x20;Merge & Apply**, and writes it to history when the operation succeeds. A failed operation leaves no snapshot behind, but it does offer you the option to roll back. Apply does not create a snapshot. You can also capture a snapshot manually and give it a label and notes.

Rollback is itself snapshotted. Rolling back creates a new history entry, so the action is auditable and you can undo it by rolling back to the entry the rollback created.

Before a rollback runs, a preview shows what changes:

- **Changes** lists the fields will rollback writes, with their current and new values.
- **Unchanged** lists fields that already match the snapshot.
- **Out of scope** lists components present on the system but absent from the snapshot. These are not affected by the rollback.

The Out of scope section matters most. A rollback returns the components in the snapshot to their captured state and leaves everything else alone, so this is where you confirm that something you care about is not going to be missed.

If the live configuration changes between the moment you view the preview and the moment you confirm, LE rejects the rollback and asks you to run the preview again against current state.

# Credential encryption

When you create a template, you can choose to encrypt credentials. LE then encrypts the protected fields of each component, such as usernames, passwords, tokens, certificates, and keys, so they are not stored or exported as plain text. Protected fields are encrypted for DeviceHub drivers, Integration connectors, Analytics, and OPC UA.

:::hint{type="warning"}
**Note:** Record the encryption key when you create the template. You cannot retrieve it later.
:::

# Roles and permissions

Applying a template rewrites system configuration, so the ability to do it is restricted. Access to the **Template** tab is controlled by the **config** permission.

- **View** lets users open the **Template** tab, see the template list and *Template Details*, and see the snapshot history. The default Viewer role has this permission.
- **Modify** lets users create, upload, edit, delete, and apply templates, and create, roll back, and delete snapshots.
- Users without **View** permission for config cannot open the **Template** tab.
- When the LE license is invalid, the template listing stays visible while edit, delete, and apply are disabled.

Applying a template rewrites system configuration, so the ability to do it is restricted.

- Users with viewer permission can see templates but cannot edit, delete, or apply them.
- Deleting a snapshot requires administrator permission.

# Tracking and visibility

Each template records who created it and when, who last updated it and when, and keeps a log of significant actions such as edits and deployments. Template application is logged in both directions: a successful apply records a timestamp, and a failure records the error alongside it.

Snapshot history is append-only and is not pruned automatically. Entries are listed newest first and show the label, timestamp, and the template name and version where one applies. Users with **Modify** permission for config can delete individual entries. The most recent snapshot cannot be deleted, so a system always retains at least one point to return to.

Creating, deleting, and rolling back to a snapshot each record an event: `config.snapshot.created`, `config.snapshot.deleted`, and `config.snapshot.rolledback`. Each event includes the snapshot and the user who started the action.

# Limitations and considerations

- **A snapshot is not a backup.** It covers configuration managed by the template system, not the whole device.
- **Declining a merge conflict cancels everything.** If you decline the overwrite prompt during **Merge & Apply**, the entire operation is abandoned rather than partially applied. Review the template before you start if you are unsure what it will overwrite.
- **Behavior in Apply mode varies by component.** Unlike the other two modes, **Apply** does not follow one predictable rule for conflicts.
- **Templates survive backup, restore, and upgrade.** They are preserved through those procedures and in High Availability configurations.
- **Renaming a device or a tag in a template creates a new one.** LE identifies devices and tags by ID rather than by name, and changing a name generates a new ID. Applying the template adds the renamed device or tag and leaves the original in place.

****

# Related topics

- [Create, import, and merge a template](docId\:zy78Ui5-eh9HtA8KdA3Sa)
- [Templates](docId\:ejYN5GxZHPCcI7vZSRFME)
- [Parameterize a template](docId\:C82odk04Fv79__nRtuwNZ)
- [Digital Twins](docId\:F7yUFDBzOQDGxnM5MB6sX)
