Render templates inside your .md

Spall renders Knap templates embedded in your Markdown files, and leaves everything else exactly as you wrote it.

How it works

Write a template between two markers. Spall renders it with your data and writes the result underneath, so one file is both the template and the finished document.

Template Generated

data.json
{
"title": "Jurassic Park",
"year": 1993,
"cast": [
"Sam Neill",
"Laura Dern"
]
}
notes.md
# Movie night
Your own notes stay put.
<!--[[[spall:begin
## {{ title }} ({{ year }})
{{ cast | list }}
spall:generate]]]-->
<!--[[[spall:end]]]-->
Including content after the template.
notes.md after spall render
# Movie night
Your own notes stay put.
<!--[[[spall:begin
## {{ title }} ({{ year }})
{{ cast | list }}
spall:generate]]]-->
## Jurassic Park (1993)
- Sam Neill
- Laura Dern
<!--[[[spall:end]]]-->
Including content after the template.

spall render writes the generated output back to the file.

spall render notes.md --data data.json

The template stays in the file

It's kept in a comment, so it's hidden when the Markdown is rendered. Run Spall to place the generated content in the same note.

Everything else is untouched

Text outside a block is preserved verbatim, so hand-written notes and generated sections can share the same file.

Safe to run again and again

Only the generated region is replaced. Run it twice with the same data and the second run changes nothing.

Spall in your terminal

Render a file in place, or check that it's up-to-date without writing anything. Run them with npx or install Spall below.

render rewrites the generated output in the file.

npx @lucasmelin/spall render notes.md --data data.json

check exits with 1 if the file is out of date, which is good for things like CI.

npx @lucasmelin/spall check notes.md --data data.json

Add --set key=value to override a variable, or --dry-run to print the result without modifying the file.

Install

Add the spall command to your machine.

npm install -g @lucasmelin/spall

Comment out your templates

Spall works wherever you can write a comment: plain Markdown, an Obsidian note, or even source code. These examples ran with --set name=Lucas.

HTML comments

The default for Markdown. The template is hidden when the file is rendered.

notes.md
<!--[[[spall:begin
Hello from {{ name }}!
spall:generate]]]-->
Hello from Lucas!
<!--[[[spall:end]]]-->

Obsidian comments

Use %% to keep templates out of Obsidian's reading view.

vault-note.md
%%[[[spall:begin
Hello from {{ name }}!
spall:generate]]]%%
Hello from Lucas!
%%[[[spall:end]]]%%

Line comments

For source files. A shared prefix like // is stripped from the template.

app.ts
// [[[spall:begin
// greet("{{ name }}");
// spall:generate]]]
greet("Lucas");
// [[[spall:end]]]

Explore

Built on Knap

Spall is open source under the MIT license. It's inspired by Cog, and uses Knap, the template language that started in Obsidian, so your templates are as Markdown-native as the files they live in.