Why Templates Update Surgically
Glimmer Internals At a Glance
Glimmer is Ember's rendering engine. It compiles templates to bytecode and uses a tag-based reactivity system to update only what changed.
What you'll learn
- Know that Glimmer compiles templates to opcodes
- Understand that tags track reactive reads
- Recognize that each tracked write bumps a revision counter
You don’t need Glimmer’s internals to ship features, but understanding the
shape of it helps explain why Ember feels fast and why @tracked works the
way it does.
Templates Become Bytecode
At build time, Glimmer parses every .hbs file into a wire format and then
into compact opcodes. At runtime, a VM walks those opcodes to build the DOM.
This is why template syntax is strict — it has to be statically analyzable.
Tag-Based Reactivity
Every reactive value (a @tracked field, an Ember Data record, a service
property) has a small object called a tag. Reading the value records the
current tag; writing the value bumps a global revision counter.
// rough mental model
let revision = 0;
class Tag {
rev = ++revision;
bump() { this.rev = ++revision; }
} A getter like get total() { return this.count + 1 } records that it depends
on count’s tag. Between frames, Glimmer asks: have any of the tags this DOM
node depends on changed revision? If not, skip it.
Only The Affected DOM Updates
Because reads are tracked at the field level, a <h1>{{@title}}</h1> only
re-renders when something writes @title. Sibling nodes that read other
values keep their bytecode validated and stay untouched.
Practical Takeaways
- Use
@trackedon raw fields. Replace arrays/objects rather than mutating. - Lean on getters; they are cached as long as their tag dependencies are
stable. Add
@cachedfor expensive ones. - Don’t reach for manual change detection — there is none. Reactivity is pull-based from the renderer’s perspective.