How Ember Octane’s @tracked Properties Cut Boilerplate and Keep Your UI in Sync
Ember Octane’s @tracked properties simplify component state management by eliminating manual set/get calls. This blog walks through how they work, a counter example, trade‑offs, and actionable steps to adopt them safely.
12 Jun 2026, 03:53 UTC

Why State Management Still Feels Like a Pain in Ember
When you first learn Ember, you’ll quickly run into the classic set and get pattern. Every time a component’s data changes, you have to call this.set('foo', value) and let Ember’s computed properties pick up the change. It works, but it clutters your code and makes it harder to reason about what actually triggers a re‑render.
With Ember Octane (starting with Ember 4.x), the framework introduced @tracked properties. They let you declare a field as “reactive” and Ember will automatically rerender the template whenever that field changes. No more manual set calls, no more magic computed properties, and a cleaner, more declarative component API.
@tracked Properties 101
In a native class component, you mark a field with the @tracked decorator:
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
export default class CounterComponent extends Component {
@tracked count = 0;
}
The framework observes the field at runtime. When this.count changes, Ember automatically schedules a re‑render of any templates that reference this.count. The magic happens under the hood with a proxy that tracks reads and writes.
Concrete Example: A Simple Counter
Below is a complete, minimal component that increments a counter each time a button is clicked. Notice that there is no set call at all.
// app/components/counter.js
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
export default class CounterComponent extends Component {
@tracked count = 0;
increment() {
this.count += 1; // direct mutation
}
}
{{!-- app/templates/components/counter.hbs --}}
<div>
<button {{on "click" this.increment}}>Increment</button>
<p>Current count: {{this.count}}</p>
</div>
To run it, create a new Ember Octane app:
ember new tracked-counter-demo --octane
cd tracked-counter-demo
ember g component counter
ember serve
Navigate to http://localhost:4200, click the button, and watch the number update instantly. The console will show a re‑render, but you don’t need to call this.set anywhere.
Trade‑offs and Caveats
- Performance: Every change to a tracked field triggers a re‑render of the entire component tree that depends on it. If you mark a large array or object as
@trackedand mutate it in place, the component may re‑render more often than necessary. Prefer primitive values or shallow copies for heavy structures. - Legacy Code: Classic components (pre‑Octane) and template‑only components cannot use
@tracked. Migrating a codebase requires refactoring to native class syntax. - Learning Curve: Teams accustomed to the old
setpattern may initially find the decorator syntax unfamiliar. Documentation and code reviews help smooth the transition. - Debugging: Since the re‑render is automatic, you may need to rely on Ember Inspector or console logs to trace why a component updated.
Practical Guidance for Adopting @tracked
- Audit Your Code: Search for
this.setandthis.getcalls. Replace them with direct property access on native class components. - Start Small: Introduce
@trackedon a handful of components first. Verify that the UI updates correctly and that performance remains acceptable. - Measure Re‑renders: Use Ember Inspector’s “Render Count” feature or add a simple
console.loginside the template to confirm that updates happen only when expected. - Guard Large Structures: For arrays or objects that change frequently, consider using
@trackedon a shallow copy or on a computed property that returns a new array. - Document Patterns: Publish a style guide that explains when to use
@trackedversus other Ember features like services or actions.
By following these steps, you can gradually shift your codebase to a cleaner, more maintainable state model without breaking existing functionality.
Conclusion
Ember Octane’s @tracked properties provide a straightforward way to keep component state and UI in sync. They reduce boilerplate, make components more declarative, and help you avoid the pitfalls of manual set calls. Just be mindful of performance when tracking large objects and plan a migration path for legacy components.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.