Who this is for. Developers and reviewers choosing, line by line, between the shorthand and an explicit getter. After this page you can recognise each failure by its symptom and apply one rule to every template.
Frontend only
The area step of the resolution runs only for a model of the frontend abstraction, the models the platform builds to render the site's pages. A model of the backend or API abstraction never reaches it, so the same expression there finds no area and throws Property heading does not exist, the same message as a typo.
What decides it is the model's abstraction, not where the template file lives: a site template rendered by backend code with a backend model behaves as backend. Code that may receive models from either side reads areas with the explicit getters, which work in every abstraction.
A real getter wins
If the model has a getter matching the name, the getter's result is returned and the area is never read. There is no error: the symptom is a plausible but wrong value. An area called name on a component prints the component's own name, not the author's text.
Names that collide: name and id on records and components alike; url, slug, fullPath, created and modified on records that have them, such as pages, posts and book pages. A plain component has no URL, so url does not collide on one.
The habit that avoids it: name areas for what they hold, such as heading, ctaUrl or personName, never after a generic property. An area that already has a colliding name is still readable with a getter: getAreaHtml('name') to print it, getAreaText('name') for plain text. Renaming it touches every template that reads it; see Where content is stored, and what a change does to it.
An unknown name throws in Smarty
A mistyped or missing area name behaves differently in each engine:
- Smarty throws, and the page fails with a server error:
Property heding does not exist in, followed by the model's class name. - Twig prints nothing and reports nothing. Core dna runs Twig without strict variables, so the failed lookup becomes
null, an empty string on the page.
Neither suits an area that is genuinely optional: one present on a newer version of a layout and not on an older one, or one read by a partial shared between layouts. Test for the area first with hasAreaWithName(), which works the same in both engines: