---
title: Template System
description: The variable substitution and dynamic configuration engine in Vane.
icon: Braces
---
import { Steps, Step } from 'fumadocs-ui/components/steps';
The Template System is Vane's dynamic engine, allowing plugin configurations to reference real-time metadata from the [KV Store](./kv-store) or specific protocol contexts (like HTTP headers or TLS SNI).
Vane uses a double-brace syntax: `{{variable_name}}`.
## Core Mechanics
The system operates as a recursive-descent parser and resolver, enabling powerful features like nested variable resolution.
### Nested Variables
Templates are resolved from the inside out. Consider the example: `{{kv.{{conn.protocol}}_backend}}`
<Mermaid
chart='
graph LR;
subgraph Step1 [Phase 1: Parse Inner]
Inner["{{conn.protocol}}"] -- Lookup --> Value1["http"]
end
subgraph Step2 [Phase 2: Construct Key]
Concat["kv. + http + _backend"] --> Key["kv.http_backend"]
end
subgraph Step3 [Phase 3: Final Resolution]
Value2["backend-01"]
end
Value1 --> Concat
Key --> Value2
'
/>
1. The inner variable `{{conn.protocol}}` is resolved first (e.g., to `http`).
2. The resulting string `kv.http_backend` becomes the key for the outer resolution.
3. The final value is looked up in the KV store using the constructed key.
### JSON Integration
The engine is not limited to plain strings. Through `resolve_inputs()`, Vane can recursively traverse complex JSON structures (Arrays and Objects), identifying and resolving every string-based template found within.
## The Resolution Pipeline
<Steps>
<Step>
### Parsing (AST Generation)
The `parser.rs` module converts the raw string into an Abstract Syntax Tree (AST) composed of `Text` and `Variable` nodes.
<Mermaid
chart="
graph LR
Raw[Raw String] --> Parser[AST Parser]
Parser --> Nodes[AST: Text + Variable Nodes]
"
/>
</Step>
<Step>
### Recursive Resolution
The `resolver.rs` module traverses the AST. If a `Variable` node contains nested parts, it recursively calls the resolver to determine the final key name.
<Mermaid
chart="
graph LR
AST[AST Nodes] --> Resolve[Recursive Resolver]
Resolve --> Nested{Nested?}
Nested -- Yes --> Resolve
Nested -- No --> Key[Final Key Name]
"
/>
</Step>
<Step>
### Context Lookup
The resolved key is passed to a `TemplateContext`. While usually linked to the connection's `KvStore`, the context can also "hijack" data directly from protocol streams.
<Mermaid
chart="
graph LR
Key[Key Name] --> Context{TemplateContext}
Context --> KV[KV Store Lookup]
Context --> Hijack[Protocol Hijacking]
KV & Hijack --> Value[Final String Value]
"
/>
</Step>
</Steps>
## Security: Injection Protection
Vane implements a critical security layer to prevent "Template Injection" attacks.
If a dynamically resolved key name (the string inside the braces) contains the characters `{` or `}`, the resolver **immediately refuses to perform the lookup**.
**Why this matters:**
Imagine an attacker provides a value that is later used as part of a template key. If they provide `{{system.admin_token}}`, and Vane naively resolves it, they could trick the engine into leaking sensitive internal variables. By banning template syntax within resolved keys, Vane ensures that data and logic remain strictly separated.
## Resource Limits
To protect the engine's performance, the following limits are enforced via environment variables:
| Variable | Default | Description |
| :------------------------- | :------ | :----------------------------------------------------- |
| `MAX_TEMPLATE_DEPTH` | `5` | Maximum recursion depth for nested variables and JSON. |
| `MAX_TEMPLATE_RESULT_SIZE` | `65536` | Maximum size (64KB) for a fully resolved string. |
| `MAX_TEMPLATE_PARSE_NODES` | `50` | Maximum nodes allowed in a single template AST. |
<Callout type="info" title="Lazy Evaluation">
Template resolution is lazy. For example, referencing `{{req.body}}` in Layer 7 will trigger the on-demand buffering of the HTTP request body only at the moment the template is resolved.
</Callout>