Every Tringify storefront theme is rendered by a template language we built ourselves. It is called Vascula, and from today it is open source under the MIT licence.
Vascula is an HTML template language and a Go library. If you have written Liquid or Jinja, you can already read it. What makes it different is what it refuses to do.
A small example
Here is a product list:
<ul>{% for product in shop.products %}
<li>{{ product.title }}</li>{% endfor %}
</ul>
Render it with a product called Assam <strong> and you get this:
<ul>
<li>Sencha</li>
<li>Assam <strong></li>
<li>Oolong</li>
</ul>
The markup is escaped. It always is. There is no raw filter, and nothing a template can write switches escaping off. Only the application that embeds Vascula can mark a value as trusted HTML.
To try it:
go get vascula.dev/vascula@latest
You need Go 1.25 or later.
Why we built it
A storefront theme is code written by one party and run with data owned by another. A merchant installs a theme. The theme reads the store's products, prices and cart. Both sides need to trust the result.
So we wanted a language with clear answers to three questions. What can this template read? What can it print? How much can it cost to run? Vascula answers each one before it renders a single page.
What a template can read
A template sees only the data roots the application allows. Reading any other name is an error, not an empty string. That catches typos early, and it means a template cannot wander into data it was never given.
The application can also ask a compiled template for every outside name it reads, with the line and column where each one is first used. Tringify uses this to check a theme section before it ever runs. You can use it to build an editor, a linter or a review step.
What it costs to run
Compiling and rendering are both bounded. There are limits on source size, tokens, nesting depth, work steps, output size and value size. A template with a runaway loop stops with an error. It does not take a server down with it.
Numbers are exact 64-bit integers, so prices in minor units stay exact. Every error carries a line and a column.
Fast enough to stop thinking about
We measured Vascula against two Liquid implementations on the same templates, data and Linux machine:
| Task | Vascula | Go Liquid | Ruby Liquid (YJIT) |
|---|---|---|---|
| Render a 48-product grid | 100 µs | 320 µs | 352 µs |
where, sort, map, join over 48 products | 8.5 µs | 27 µs | 37 µs |
| The same, with 150-field products | 10.5 µs | 30 µs | 38 µs |
| Compile the grid template | 9 µs | 32 µs | 89 µs |
Go Liquid is osteele/liquid. Ruby Liquid is Shopify's implementation. The grid template is part of Vascula's benchmark suite, and the performance page has the details.
What is in the box
- 50 built-in filters.
- Ranges, loops and conditionals you will recognise.
- Reusable partials rendered with their own arguments.
- Your own filters, tags and form kinds, defined by the host application.
- No third-party dependencies.
The syntax will feel familiar, but Vascula is not a Liquid clone. Where it behaves differently, the Coming from Liquid page lists every difference.
Docs for people and for agents
The documentation at vascula.dev is written to be read by people and by AI coding agents. Every page is also published as plain Markdown: add .md to any page URL. There is an /llms.txt index and a single-file /llms-full.txt.
Every template example in the docs is also a test. If an example stops producing the output shown, the build fails. What you read is what the library does.
The name
Vascula is loosely Latin for "little vessels": the veins that carry what a page needs to the place it is needed. That is the job of a template. Our artwork shows it as a pixel-art greenhouse, with glowing green vines running between the rooms.
Early, and honest about it
This is v0.1.0, the first public release. It already renders every Tringify storefront. Until 1.0, a release may still change the language or the Go API, so pin a version and read the changelog before upgrading.
We would like your help getting to 1.0. Read the docs, try the tutorial, and open an issue or a pull request on GitHub. Security reports go privately to developers@tringify.com.
