Ember.js Cheat Sheet
A reference for Ember's CLI commands, Glimmer components, tracked properties, and route/model conventions for building web apps.
Ember CLI Commands
Scaffolding and running an Ember application.
ember new my-appember generate component my-component # shorthand: ember g component my-componentember generate route posts # shorthand: ember g route postsember serveember build --environment=productionember test
Glimmer Component
The modern component class using tracked properties and actions.
// app/components/counter.jsimport 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++; }}/* app/components/counter.hbs<button {{on "click" this.increment}}> Count: {{this.count}}</button>*/
Core Concepts
The conventions and building blocks Ember apps rely on.
- @tracked- decorator marking a property as reactive; templates auto-update when it changes
- @action- decorator that binds 'this' correctly for a method used as a template event handler
- Ember Data- the built-in ORM-like library for modeling, fetching, and caching API records
- Route- defines what model to load and which template to render for a URL
- {{outlet}}- template placeholder where a route's nested child template renders
- Glimmer components- the modern lightweight component class, replacing classic Ember components
- Ember CLI- the official build tool and scaffolding CLI (ember generate, ember serve, ember build)
Routes & Models
Mapping URLs to routes and loading data for them.
// app/router.jsRouter.map(function () { this.route('posts', function () { this.route('show', { path: '/:post_id' }); });});// app/routes/posts/show.jsimport Route from '@ember/routing/route';export default class PostsShowRoute extends Route { model(params) { return this.store.findRecord('post', params.post_id); }}
Element Modifiers
Modifiers attach imperative DOM behavior to an element and clean up automatically when it's removed.
// app/modifiers/click-outside.jsimport { modifier } from 'ember-modifier';export default modifier((element, [callback]) => { function handleClick(event) { if (!element.contains(event.target)) callback(event); } document.addEventListener('click', handleClick, true); return () => document.removeEventListener('click', handleClick, true);});/* template usage:<div {{click-outside this.closeMenu}}>...</div>*/
Services & Dependency Injection
Services are long-lived singletons injected into routes, controllers, and components.
// app/services/cart.jsimport Service from '@ember/service';import { tracked } from '@glimmer/tracking';export default class CartService extends Service { @tracked items = []; addItem(item) { this.items = [...this.items, item]; }}// app/components/add-to-cart.jsimport Component from '@glimmer/component';import { inject as service } from '@ember/service';import { action } from '@ember/object';export default class AddToCartComponent extends Component { @service cart; @action add() { this.cart.addItem(this.args.product); }}
Ember Data Relationships & Adapters
Defining model relationships and customizing how records are fetched over the wire.
// app/models/post.jsimport Model, { attr, hasMany, belongsTo } from '@ember-data/model';export default class PostModel extends Model { @attr title; @belongsTo('author') author; @hasMany('comment') comments;}// app/adapters/application.jsimport JSONAPIAdapter from '@ember-data/adapter/json-api';export default class ApplicationAdapter extends JSONAPIAdapter { host = 'https://api.example.com'; namespace = 'v1';}
Testing with QUnit & Ember Test Helpers
Rendering tests use @ember/test-helpers with async DOM interaction helpers.
import { module, test } from 'qunit';import { setupRenderingTest } from 'ember-qunit';import { render, click, find } from '@ember/test-helpers';import { hbs } from 'ember-cli-htmlbars';module('Integration | Component | counter', function (hooks) { setupRenderingTest(hooks); test('it increments on click', async function (assert) { await render(hbs`<Counter />`); await click('button'); assert.strictEqual(find('output').textContent.trim(), '1'); });});
Advanced Ember Concepts
Patterns that show up once you move past scaffolding a first component.
- Route hooks- beforeModel/model/afterModel run in sequence and can each return a Promise to pause transitions
- Named + query params- routes support dynamic segments (:post_id) and controllers declare queryParams for URL-driven state
- Ember Concurrency- addon providing cancelable, restartable async 'tasks' to avoid race conditions in UI-driven async work
- Octane edition- the modern Ember programming model: native classes, Glimmer components, @tracked, and Glimmer template syntax
- Engines- lazily-loadable, isolated sub-applications for splitting a large Ember app's bundle
- willDestroy- lifecycle hook for cleaning up subscriptions/timers on a Component or Service before it's torn down
- RSVP / auto-run loop- Ember batches DOM updates and async work inside runloop queues (actions, render, destroy) for consistency
Ember favors convention over configuration -- file location determines behavior (app/routes/posts/show.js maps to the posts.show route), so learning the folder conventions is more valuable than memorizing individual APIs.