Posted on ::

I migrated this site to Zola 0.23, released yesterday with the new Tera 2 template engine (Well, 0.23.1 from today actually). When I chose Zola last March, I praised its creator for not chasing the latest fad. I stand by it: 0.23 breaks my templates, but it does it in a cleaner way.

Tera 2 removes the old macros and imports, and Zola 0.23 removes the shortcodes. Everything is now a namespaced component. A macro that I used to import and call like this:

{% import "macros.html" as utils %}
{% macro show_link(url) %}<a href="{{ url }}">{{ url }}</a>{% endmacro %}
...
{{ utils::show_link(url=link) }}

is now a global component with no import at all:

{% component site.show_link(url) %}<a href="{{ url }}">{{ url }}</a>{% endcomponent %}
...
{{<site.show_link url={link} />}}

The big philosophical change: components are global and no longer inherit the caller context. Every variable — page, section, config, current_path — must be passed explicitly as an argument. More verbose, but it makes dependencies visible. I like that more and more: one way to do it, and it is visible.

Tera 2 is also strict: a missing variable is now a hard error. My templates use optional chaining (?.) for anything optional, which catches typos at build time instead of silently rendering broken pages.

What concretely changed:

  • concat and slice filters are gone → array spread and slicing
  • get_env is gone → config.mode == "serve" for local editor links
  • include ... ignore missing is invalid → empty hook templates
  • get_page with fatal=false → canonical path with lang and allow_missing=true
  • get_taxonomy_url with nameterm

The migration guide was my best map through all of this.

I use the Apollo theme as a git submodule, and as it does not support Zola 0.23 yet, I keep a small local template-only patch of it until upstream migrates. The design, CSS, and JavaScript are untouched: this was a syntax migration, not a redesign, and I did not rewrite my post contents either.

Use of AI🔗

I chose to have AI help me migrate my site. It worked flawlessly, so I encourage you to do the same. For reference here is the first prompt I gave it to prepare the plan for the migration:

I want you to only create a document for agents ai/agents/tera2.md to summarize
how tera2 of Zola 0.23 differs from tera1 of Zola 0.22, and the plan to migrate
my site from Zola 0.23 to 0.22.

Examine the differences between Zola 0.22 and 0.23, not just tera.

Docs:
Tera2 https://keats.github.io/tera/
Migration guide Tera1 → Tera2 https://github.com/Keats/tera/blob/master/MIGRATION.md
Zola 0.23 docs https://www.getzola.org/documentation/getting-started/overview/

Take your time, be thourough, but do not modify yet any file of my site except
the ones in ai/agents/ and AGENTS.md

Then, plan the migration of this site to zola 0.23
1. not modifying the contents of the posts unless necessary for tera2 changes
2. not changing the look and feel, the UI of the site
3. adapting the various templates
4. changing my local copy of the Apollo theme I use if needed.
   These changes are a stopgap measure until upstream apollo is migrated to Zola 0.23

I use Deepseek v4 flash normally, but chose to use GPT-5.6 Luna for this migration as it is currently quite cheap and I trust it more to not go change unecessary files. And Deepseek as no vision, so it cannot check the actual visual results of changes. It helped me greatly for this migration, without any problems.

Summary of AI actions:🔗

  • Replaced Tera 1 macros, imports, self:: calls, and macro namespaces with namespaced Tera 2 components in the root templates and Apollo templates.
  • Converted the local language-listing, page, navigation, debug, file inclusion, and section-name helpers to components.
  • Converted the site shortcode implementations to components in templates/macros/shortcodes.html.
  • Converted active post calls from the removed Zola shortcode syntax to Tera 2 component syntax. This includes YouTube, snapshots, attachments, Mermaid, static-file inclusion, legacy overlays, obsolete notices, and SVG icons.
  • Passed explicit base_path values to components that used to receive page.path implicitly from Zola shortcodes.
  • Updated get_page calls to use the canonical path with lang="fr" and allow_missing=true.
  • Updated get_taxonomy_url calls from name to term.
  • Replaced the removed get_env call with config.mode == "serve" for the local editor links.
  • Replaced the removed concat and slice filters with Tera 2 array spread and slicing, and changed the object test to map.
  • Added empty Apollo hook templates because Tera 2 no longer accepts include ... ignore missing.
  • Updated dev/bin/site-check to recognize the new legacy component syntax.
  • Updated static/ZOLA to zola 0.23.0.
Table of Contents