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:
concatandslicefilters are gone → array spread and slicingget_envis gone →config.mode == "serve"for local editor linksinclude ... ignore missingis invalid → empty hook templatesget_pagewithfatal=false→ canonical path withlangandallow_missing=trueget_taxonomy_urlwithname→term
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.23I 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_pathvalues to components that used to receivepage.pathimplicitly from Zola shortcodes. - Updated
get_pagecalls to use the canonical path withlang="fr"andallow_missing=true. - Updated
get_taxonomy_urlcalls fromnametoterm. - Replaced the removed
get_envcall withconfig.mode == "serve"for the local editor links. - Replaced the removed
concatandslicefilters with Tera 2 array spread and slicing, and changed theobjecttest tomap. - Added empty Apollo hook templates because Tera 2 no longer accepts
include ... ignore missing. - Updated
dev/bin/site-checkto recognize the new legacy component syntax. - Updated
static/ZOLAtozola 0.23.0.