Using @tracked Properties in Ember Octane for Reactive UI Updates
Learn how Ember Octane's @tracked decorator replaces observers with automatic Glimmer VM tracking, illustrated by a counter component and migration steps.
16 Feb 2026, 00:48 UTC

The Problem with Observers and Computed Properties
In many Ember applications, developers keep the UI in sync with data by writing observers or computed properties. These mechanisms require manual dependency tracking and can produce hard‑to‑trace bugs when the dependency list is incomplete or when observers fire unexpectedly.
How @tracked Works in Ember Octane
Ember Octane introduced the @tracked decorator from @glimmer/tracking. When a property is marked @tracked, the Glimmer VM records every template expression or helper that reads the property during rendering. If the property later changes, the VM marks only those recorded parts as dirty and re‑runs them, leaving the rest of the component untouched.
Worked Example: A Counter Component
The following component shows a simple counter that increments when a button is clicked. No observers or computed properties are needed.
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
export default class CounterComponent extends Component {
@tracked count = 0;
@action
increment() {
this.count += 1;
}
}
{{this.count}}
+1
When the increment action runs, this.count changes. The Glimmer VM knows that the template expression {{this.count}} accessed this property during the last render, so it updates only that text node. The button itself is unaffected.
Trade‑offs and Migration Considerations
- Learning a new mental model: developers must think in terms of automatic tracking rather than manual dependencies.
- Existing codebases may contain many observers; migrating them can be effort‑intensive, especially in large applications.
- For asynchronous data flows (e.g., raw
Promiseobjects), tracked properties work best when paired with libraries like Ember Data that expose tracked state; plain promises may need manual wrapping.
Actionable Steps and Verification
- Check your Ember version: run
ember -vin the project root (requires read access to the repository). Ensure the version is 3.13 or higher. - Confirm that
@glimmer/trackingappears inpackage.jsonunderdependenciesordevDependencies. - Run the component’s acceptance test:
ember test --filter "counter-component"(or execute the full test suite withember test). - In the test, invoke the
incrementaction and assert that the DOM node containing the count updates without triggering any observer callbacks. - As a quick manual check, start the app with
ember serve, click the button, and verify the displayed number increments instantly.
By adopting @tracked for new components and gradually migrating existing observers, you can reduce boilerplate and improve the reliability of UI updates.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.