Generate, Extend Service, Add Tracked State
Defining a Service
Running ember generate service scaffolds a singleton class. Extend the Service base class and add tracked state.
What you'll learn
- Generate a service with the ember-cli generator
- Extend the Service base class
- Add reactive state with the tracked decorator
A service is a singleton class owned by the application. It’s the canonical place to put cross-cutting state and behavior — auth, websockets, feature flags, a cart, a router wrapper.
Generate
ember generate service auth This creates app/services/auth.js:
import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class AuthService extends Service {
@tracked currentUser = null;
async login(credentials) {
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(credentials),
});
this.currentUser = await res.json();
}
logout() {
this.currentUser = null;
}
} Reactive By Default
Because currentUser is @tracked, anything reading auth.currentUser —
templates, getters, other services — updates automatically when it changes.
Lifecycle
Services are instantiated lazily on first lookup and live for the lifetime of the app instance. In tests, each test gets a fresh app instance, so services are reset between tests.
Override willDestroy if you need to clean up (close sockets, unsubscribe,
etc.):
willDestroy() {
this.socket?.close();
super.willDestroy();
} Where Services Live
Every service file lives at app/services/<kebab-case-name>.js. The filename
matches the lookup name — auth.js ↔ 'auth'.