Inject Once, Use as this.foo
Dependency Injection With service
The service decorator pulls a service out of the container into the current class — components, routes, services can all inject each other.
What you'll learn
- Inject by name to match the service filename
- Rename locally with the explicit form
- Inject into routes, components, and other services
Ember’s DI container is one of its quiet superpowers. Every component, route,
service, and controller is owned by the same container, and you reach into it
with the @service decorator.
Inject By Name
import Component from '@glimmer/component';
import { service } from '@ember/service';
export default class Nav extends Component {
@service auth;
@service router;
@service store;
} The decorator looks up service:auth (the file at app/services/auth.js) and
assigns the singleton to this.auth.
Renaming Locally
If the local property should be different from the service name, pass an explicit name:
@service('store') db;
@service('intl') i18n; This is handy when “store” or “intl” conflict with a domain concept in this class.
Across All Class Types
The same @service works in routes, controllers, components, and even other
services:
// app/services/cart.js
import Service from '@ember/service';
import { service } from '@ember/service';
export default class CartService extends Service {
@service store;
@service auth;
} Beware circular dependencies between services — keep the graph a DAG.
How Lookup Works
Behind the scenes, getOwner(this).lookup('service:auth') is happening for
you. You can do it manually when needed (e.g., a factory function with no
class context) — see the Owner lesson.
Test Stubs
In tests, you can register a stub before the test runs:
class FakeAuth extends Service {
currentUser = { name: 'Test User' };
}
this.owner.register('service:auth', FakeAuth); Now every @service auth in the test gets the fake.