The moment you templatise firewall config in FortiManager, you hit the same wall: 90% of the config is identical across every branch, but 10% — the WAN interface, the LAN subnet, the BGP router-id, the site code — is unique per device. Hard-code that 10% and the template only fits one box. Metadata variables are how you carve out the unique parts so one template fits the whole fleet.

The idea

A metadata variable is a named value that FortiManager resolves per device at install time. You write {{lan_subnet}} once in a shared CLI template; each device supplies its own value; the rendered config is unique but the source is single.

config system interface
    edit "{{lan_if}}"
        set ip {{lan_gateway}} {{lan_mask}}
        set allowaccess ping
    next
end

Install this to three devices and each gets its own interface, IP and mask — from one template.

One template, variables resolved per device resolved per device · at install CLI TEMPLATE {{wan_if}} · {{lan_ip}} · {{router_id}} one source of truth FGT-01 wan1 · 10.1.0.1 · .1 FGT-02 wan1 · 10.2.0.1 · .2 FGT-03 wan2 · 10.3.0.1 · .3 {{ var }} = per-device value
FIG.01 / One template, metadata variables resolved to a unique config per device at install time
The template holds the logic; the variables hold the exceptions. Keeping those two separate is the whole trick — the 90% that's identical lives in one place, the 10% that differs lives in a small, reviewable dataset.

Defining the variables

Metadata variables live under Policy & Objects → Object Configurations → Advanced → Metadata Variables (exact path shifts a little by version). Create the variable, mark it required or give it a default, then set a per-device value on each managed device.

For a fleet, setting them one-by-one in the GUI defeats the purpose — export the device list, fill the values in a spreadsheet, and set them through the JSON-RPC API so the data is the source of truth, not the clicks. The point is that the values become a small, reviewable dataset and the logic stays in one template.

Where it pays off

  • IPsec / ADVPN spokes — every spoke runs identical tunnel logic; only the overlay IP and WAN interface differ. (See ADVPN at Scale with FortiManager Templates for the full fabric build.)
  • BGP — shared neighbour logic, per-device router-id.
  • Naming and tagging — a site_code variable drives interface descriptions, hostnames and policy comments so the config is self-documenting.

Guardrails

  • Default carefully. A required variable with no value fails the install loudly — which is what you want. A variable with a wrong default fails silently by shipping a bad config. Prefer required-with-no-default for anything security-relevant.
  • Preview before you push. The Install Wizard's preview renders the variables for real — read the diff on a pilot device before you touch the fleet.
  • One source of truth. Once a value is a metadata variable, stop editing it directly on the device. The next install will overwrite local drift, and you'll spend an afternoon working out why.

Templates give you consistency; metadata variables give you the exceptions without breaking the consistency. Together they're the difference between managing a fleet and managing fifty snowflakes.