Luma Documentation
Complete reference for the Luma template engine.
Quick Links
- API Reference - Complete API documentation
- Jinja2 Migration Guide - Migrate from Jinja2
- Integration Guides - Framework integrations
- Whitespace Control - Smart whitespace handling
Language Reference
Variables
Simple Variables
$name
$user.email
$config.server.host
Complex Expressions
${1 + 2}
${price * quantity}
${users[0].name}
${dict["key"]}
Variable Assignment
@let name = "Alice"
@let age = 30
@let items = ["apple", "banana", "cherry"]
Control Flow
If Statements
@if condition
True branch
@end
@if x > 10
Large
@elif x > 5
Medium
@else
Small
@end
For Loops
@# List iteration
@for item in items
- $item
@end
@# Dictionary iteration
@for key, value in pairs(dict)
${key}: $value
@end
@# Array iteration with index
@for i, value in ipairs(array)
${i}. $value
@end
@# Tuple unpacking
@for name, age in users
$name is $age years old
@end
Loop Variables
@for item in items
Index: $loop.index (1-based)
Index0: $loop.index0 (0-based)
First: $loop.first (boolean)
Last: $loop.last (boolean)
Length: $loop.length
Previous: $loop.previtem
Next: $loop.nextitem
@# Cycle through values
$loop.cycle("odd", "even")
@end
Loop Control
@for item in items
@if item.skip
@continue
@end
@if item.stop
@break
@end
Process: $item
@end
While Loops
@let count = 0
@while count < 10
Count: $count
@let count = count + 1
@end
Filters
Filters transform values using the pipe operator:
$value | filter
$value | filter(arg1, arg2)
$value | filter1 | filter2 | filter3
String Filters
$text | upper
$text | lower
$text | capitalize
$text | title
$text | trim
$text | replace("old", "new")
$text | truncate(50)
$text | center(80)
$text | wordwrap(60)
$text | indent(4)
$text | striptags
$text | urlencode
$text | escape
List Filters
$items | length
$items | first
$items | last
$items | join(", ")
$items | sort
$items | reverse
$items | unique
$items | sum
$items | min
$items | max
$items | map("name")
$items | select("active")
$items | reject("deleted")
$items | selectattr("status", "active")
$items | rejectattr("hidden", true)
$items | groupby("category")
$items | batch(3)
$items | slice(2)
Dictionary Filters
$dict | keys
$dict | values
$dict | items
$dict | dictsort
Type Filters
$value | default("fallback")
$value | default(0)
$obj | attr("property")
$data | tojson
Numeric Filters
$number | round
$number | round(2)
$number | abs
Named Arguments
$text | truncate(length=50, killwords=true, end="...")
$text | wordwrap(width=80, break_long_words=false)
$text | indent(width=4, first=false)
See API Reference - Filters for complete list.
Tests
Tests check conditions using is:
@if value is defined
@if value is undefined
@if value is none
@if value is string
@if value is number
@if value is boolean
@if value is table
@if value is callable
@if value is iterable
@if value is mapping
@if value is sequence
@if value is odd
@if value is even
@if value is divisibleby(3)
@if value is lower
@if value is upper
Negation
@if value is not defined
@if value is not none
@if x is not even
See API Reference - Tests for complete list.
Membership Operators
@if "key" in dict
@if item in list
@if "sub" in string
@if x not in collection
Template Inheritance
Extends
Base Template (base.luma):
<!DOCTYPE html>
<html>
<head>
@block head
<title>Default Title</title>
@end
</head>
<body>
@block content
Default content
@end
</body>
</html>
Child Template:
@extends "base.luma"
@block head
<title>My Page</title>
@end
@block content
<h1>Hello, World!</h1>
@end
Super Function
Call parent block content:
@extends "base.luma"
@block content
$super()
Additional content
@end
Scoped Blocks
@for user in users
@block user_card scoped
<div>$user.name</div>
@end
@end
Includes
@# Simple include
@include "header.luma"
@# Include with context
@include "card.luma" with title="Hello", content="World"
@# Include with namespace
@include "config.luma" ignore missing
Macros
Define Macros
@macro button(text, type="default")
<button class="btn btn-$type">$text</button>
@end
@macro card(title, content)
<div class="card">
<h3>$title</h3>
<p>$content</p>
</div>
@end
Call Macros
@call button("Click Me")
@call button("Submit", type="primary")
@call card("Title", "Content goes here")
Import Macros
@# Import all macros
@import "macros.luma"
@# Import specific macros
@from "macros.luma" import button, card
@# Import with alias
@from "macros.luma" import button as btn
Call with Caller
@# Define macro that accepts caller
@macro list(items)
<ul>
@for item in items
<li>$caller(item)</li>
@end
</ul>
@end
@# Use with caller block
@call(item) list(["a", "b", "c"])
Item: $item
@end
Do Blocks
Execute code without output:
@do
@let result = expensive_calculation()
@let formatted = result | format
@end
Result: $formatted
Set Blocks
Multi-line variable assignment:
@let html_content
<div>
<h1>Title</h1>
<p>Content</p>
</div>
@end
$html_content
Namespaces
Mutable objects for variable management:
@do
@let ns = namespace(count=0, found=false)
@end
@for item in items
@if item.match
@do
ns.found = true
ns.count = ns.count + 1
@end
@end
@end
Found: $ns.found, Count: $ns.count
Comments
@# Single-line comment
@comment
Multi-line comment
Can span multiple lines
@end
Raw Blocks
Disable template processing:
@raw
This $variable will not be processed
@if statements are ignored too
@end
Jinja2 syntax:
{% raw %}
{{ this }} will not be processed
{% endraw %}
Autoescape
Control HTML escaping:
@autoescape true
$user_input @# Will be escaped
@end
@autoescape false
$trusted_html @# Will not be escaped
@end
Mark content as safe:
@let safe_html = html | safe
$safe_html @# Won't be escaped even in autoescape blocks
Whitespace Control
Smart Preservation (Default)
Luma automatically preserves indentation for all file types:
# YAML example - indentation preserved automatically
containers:
@for container in containers
- name: $container.name
image: $container.image
@end
Dash Trimming
For precise control, use dash (-) syntax:
@# Trim before
text-$value
@# Trim after
$value-text
@# Trim both
text-$value-more
@# Trim with directives
-@if condition
content
@end
Inline Mode
Use semicolons for inline directives:
Status: @if active; Online @else Offline @end
Result: @for i in {1,2,3}; $i @end
Jinja2 Trim Syntax
{%- if condition -%}
{{- value -}}
{%- endif -%}
See Whitespace Control Guide for details.
Jinja2 Syntax
Luma supports full Jinja2 syntax for compatibility:
{% set name = "World" %}
Hello, {{ name }}!
{% if condition %}
True
{% elif other %}
Maybe
{% else %}
False
{% endif %}
{% for item in items %}
- {{ item }}
{% endfor %}
{% macro button(text) %}
<button>{{ text }}</button>
{% endmacro %}
{{ button("Click") }}
Migration:
luma migrate template.j2 > template.luma
Best Practices
1. Use Native Syntax for Readability
@# Preferred - clean and readable
@if condition
$value
@end
@# Also works but less clean
{% if condition %}
{{ value }}
{% endif %}
2. Leverage Smart Whitespace
# No manual trimming needed
apiVersion: v1
kind: Service
metadata:
name: $service_name
spec:
@if ports
ports:
@for port in ports
- port: $port.port
targetPort: $port.targetPort
@end
@end
3. Use Macros for Reusability
@# Define once
@macro alert(message, type="info")
<div class="alert alert-$type">$message</div>
@end
@# Use many times
@call alert("Success!", type="success")
@call alert("Warning!", type="warning")
4. Filter Data Appropriately
@# Always escape user input for HTML
<div>${user_input | escape}</div>
@# Use appropriate filters
$email | lower
$name | title
$date | date_format
5. Organize Templates
templates/
├── base.luma # Base layouts
├── components/ # Reusable components
│ ├── header.luma
│ └── footer.luma
├── macros/ # Macro libraries
│ ├── forms.luma
│ └── cards.luma
└── pages/ # Page templates
├── home.luma
└── about.luma
Performance Tips
1. Compile Once, Render Many
local luma = require("luma")
-- Compile once
local compiled = luma.compile(template_string)
-- Render many times (fast!)
for i = 1, 1000 do
local result = compiled(context)
end
2. Enable Template Caching
local luma = require("luma")
luma.enable_cache()
-- Templates are cached automatically
for i = 1, 1000 do
luma.render(template_string, context)
end
3. Use LuaJIT
# Use LuaJIT for 3-5x performance improvement
luajit your_script.lua
4. Minimize Filter Chains
@# Less efficient
$value | filter1 | filter2 | filter3 | filter4
@# More efficient - combine when possible
$value | combined_filter
Error Handling
Syntax Errors
Error: Syntax error in template at line 5, column 12
Expected 'end' but found 'elif'
@if condition
something
@elif other <-- Error here
Undefined Variables
-- Handle missing variables
local luma = require("luma")
luma.strict_undefined = false -- Don't error on undefined
@# Use defaults for safety
${maybe_undefined | default("fallback")}
@# Check if defined
@if value is defined
$value
@else
Not available
@end
Validation
# Validate template syntax
luma validate template.luma
# Validate all templates
luma validate templates/**/*.luma
Next Steps
- API Reference - Detailed API documentation
- Examples - Real-world examples
- Integration Guides - Framework integrations
- Contributing - Contribute to Luma