· 4 min read · By Jason Dorn

We Moved EZdoc's Templates to Liquid (and Why It Doesn't Change Anything for You)

We moved EZdoc's template engine to Liquid — the same engine Shopify uses. Nothing changes for you: the same placeholders, loops, and IF/THEN logic still work. Here's what changed under the hood, and why.

Editorial illustration on cream: two tangled wires — a patched-together Python and homemade-Jinja engine — merge through a junction into one clean teal Liquid pipe, whose droplet fills a document template showing {{ }} placeholders. Headline: Now running on Liquid.

Every so often we change something deep under the hood that you'll never notice — and honestly, that's the whole point. Last week we swapped the engine that powers every EZdoc template. Here's what changed, why we did it, and the short answer to "do I need to do anything?" (you don't).

The short version:

  • We moved EZdoc's templates to Liquid, the open-source engine Shopify built to safely run millions of user-made templates.
  • Everything you already do works exactly the same — {{ placeholders }}, loops, and IF/THEN logic are unchanged.
  • We dropped a Python dependency along the way, so EZdoc now runs on one clean Ruby stack.
  • You don't need to change a thing. If you hand-write template syntax, there's a 30-second cheat sheet at the bottom.

What actually changed

EZdoc used to render templates with a patched-together setup: part Python (a library called docxtpl) and part our own code approximating the Jinja2 templating language. It worked — but it was two languages held together with tape, and it occasionally tripped over template features it didn't fully understand.

EZdoc is a Ruby on Rails app. So we moved templating to Liquid, which is itself a Ruby library. Now the entire pipeline — generate a template, fill it with your data, render the PDF — runs in one language, natively. No Python sidecar, fewer moving parts, fewer things that can quietly break.

Why Liquid

Liquid isn't some obscure choice. It's the engine behind Shopify storefronts, Jekyll websites, and a long list of tools that need to run templates written by regular people without things blowing up. It's sandboxed by design, battle-tested at enormous scale, and — conveniently for us — written in Ruby.

It also speaks the language you already know. A value is {{ customer_name }}. A loop is {% for item in items %}. A condition is {% if total > 1000 %}. If you've ever built an EZdoc template, you've effectively already been writing Liquid.

"Wait — what about uploading my own Word file?"

Straight answer: we retired Word/.docx uploads. That used to be a headline feature, so I won't pretend it wasn't a real change.

Here's the thinking. We made a bet that we could make generating a template so good you wouldn't want to hunt down and upload your own. Describe what you need — an invoice, a certificate, an offer letter — and EZdoc designs the whole thing for you: layout, headers, placeholders, all of it, in a few seconds. Those generated templates run on Liquid, and they tend to come out cleaner than a decade-old Word file with mystery formatting baked in.

If you've been uploading .docx files, generate a fresh template instead. It's faster, and you can tweak it from there.

What you need to do

Nothing. Your existing templates, CSVs, and API calls keep working exactly as before.

The only people who'll notice anything are those who hand-write template syntax — and even then, the differences from Jinja are tiny:

Coming from Jinja? The 30-second cheat sheet

  • {{ name }}, {% for %}, and {% if %} are identical — no change.
  • Set a variable with {% assign x = "..." %} (Liquid) instead of {% set %}.
  • Default values use a colon: {{ price | default: "0" }} instead of default("0").
  • Filter names differ slightly: {{ name | upcase }}, not upper.
  • Full reference: the official Liquid docs.

That's the whole list.


Boring infrastructure changes are my favorite kind of update: you didn't have to lift a finger, and the product got a little more solid underneath you. Now back to building.

— Jason