Core dna renders server-side sites with Smarty or with Twig, one engine per site, and treats the two as peers. This guide is the one place both are documented: what they share, each engine's language and the platform's additions and limits, the two side by side, and translation.
L1–L2
Unit 01 · The shared model
Two engines, one platform
The shared modelPage 1 of 25Updated
A Core dna site renders its templates with Smarty or with Twig, chosen by one site setting. What that setting changes (syntax, the helpers the platform registers, the security model), the much longer list of what it does not, and what happens to a template written for the other engine.
Who this is for. Every developer about to write templates for a server-rendered Core dna site, whichever engine it uses. Afterwards you will know where a site's engine is set, what the choice changes and what it leaves alone, so that you treat it as a choice of syntax rather than of architecture.
One setting per site
The engine is the site setting Globals.template.engine. Its value is Smarty, the default, or Twig. A site that sets nothing renders with Smarty. A site on Twig carries the value in the .settings.json file at the root of its site folder, beside templates/:
The value is case-sensitive. The platform builds the engine's class name from it, so Smarty and Twig work and twig stops the site from rendering at all.
The file wins. A value in .settings.json takes precedence over settings saved in the admin. The platform never serves a file whose name starts with a dot, so the file is not visible from the browser.
It applies to everything the site renders: page and component templates, error pages, and the template code typed into the admin for jobs, discount conditions, shipping methods and search facets (Rendering a template from a string).
Everything below happens before the engine is involved, or is written once and handed to whichever engine the site uses. None of it changes with the setting.
Mechanism
Where it is explained
Routing: which URL reaches which controller, and which record it loads
A site's content model, its URLs and its admin setup can therefore move from one engine to the other untouched. Only the files under templates/ change.
Coercion filters, its own empty test, json_decode, debug_vars, its own set tag (list)
Security model
A policy that lists the PHP functions a template may call and blocks the rest
No sandbox: no list to check calls against
Escaping
Off unless you ask
Also off: the platform switches Twig's autoescaping off
A method the record does not offer
An error that names the method
Empty output, no error
A template file changed on production without a deploy
Recompiled on the next request
Served from the compiled copy until the cache is cleared
The Comparing and porting unit sets the two dialects next to each other construct by construct, and covers the differences that cause visible bugs.
The same folder and the same extension
Both engines read the same templates/ folder, and both read files ending in .html. The extension never selects an engine: a site's engine parses every template the site renders, whatever its name. The admin offers files ending in .html, .tpl or .twig from the site's own templates/ folder as layout templates, so a Twig site may use either extension; most keep .html.
A few templates the platform ships exist once per engine. The Smarty version keeps the plain name and the Twig version adds -twig before the extension: the sign-in, consent and remember-me screens under o-auth/frontend/, and errors/oauth.html. The passkey screen is the exception: both versions carry a suffix, passkey-add-smarty.html and passkey-add-twig.html. To restyle one of these on a Twig site, override the -twig file, such as templates/o-auth/frontend/login-twig.html.
A template written for the other engine
A site has one engine, so a template in the other dialect is not rendered by the other engine: it is read by the site's own, with results that depend on the direction.
Twig syntax on a Smarty site.{% if %} tags and {# #} comments are syntax errors, so the template fails to compile and the page errors. A bare {{ value }} is printed as it stands.
Smarty syntax on a Twig site. Single braces mean nothing to Twig, so {$page->getName()} and {if} are printed on the page as text, with no error.
So a snippet copied from the wrong engine either breaks the page or leaks its source onto it. Choosing an engine for a new site gives the recommendation that follows: one engine per site, for good.