Build an Offline Demo of your Ember App with Ember CLI Mirage

Our client wanted a demo version of their Ember app to take to trade shows, use for sales demos, etc. Ideally, it would run on a laptop with no internet connection and not require the use of any developer tools. We decided to run the Ember app against a mocked backend.


After briefly surveying available options for demo backends, we selected Ember CLI Mirage, for a couple reasons:

  • It runs entirely in the browser, with no actual server required.
  • It doesn’t depend on Ember Data (which our app doesn’t use).

Alex and I spent a couple days spiking out whether it could do everything we needed, and then integrated it with our app. The documentation is pretty good, so I won’t go into all the setup. Instead, here are some highlights from our implementation.

Keep a Tidy Configuration

For starters, in order to isolate demo mode from our existing development, test, and production environments, we disabled mirage globally, and put its configuration behind an environment variable:

ENV['ember-cli-mirage'] = {
  enabled: false // off everywhere but demo

if (process.env.DEMO_MODE) {
  ENV['ember-cli-mirage'] = {
    enabled: true

  ENV.APP.FEATURE_X = false;

This enables us to run with DEMO_MODE=true ember server, or after placing the command in package.json’s scripts section, yarn demo.

Test It

We have Mirage disabled by default in our test environment in order to not interfere with our large suite of existing tests, but we start it manually for two new types of tests:

Demo Acceptance Tests: These click around the app as it runs against the mirage backend with its fixture data, proving that it works as desired.

Data Validation Tests: As the primary backend changes over time, demo mode’s fixture data could easily fall out of sync. To detect this granularly, we walk over all the demo data, serialize each record, and verify that it produces a valid client model. (We happen to have strict models, generated from backend types.)

Rarely-used demonstration features can easily be neglected and rot; these tests will help protect ours from breaking as the rest of the app evolves.

Make a Portable Build

When configured correctly, an Ember app can run from disk, with no webserver required. It’s a little tricky to get routing and asset paths to work correctly with file:// URLs; here’s the magic incantation to drop in the demo config section:

ENV.rootURL = '';
ENV.locationType = 'hash';
  • rootURL “identifies the path at which an Ember application is served so Ember’s router can know which path segments to ignore.”
  • locationType governs how Ember interacts with the browser URL.

You may find that these changes break some hardcoded <a hrefs, especially if they were pointing at routes within your app. Now’s a great time to switch them over to link-to, which references routes symbolically and is immune to these configuration changes.

With these in place, running a demo is as simple as double-clicking index.html!

Do More Cool Things

Relevant miscellany:

  • Hook into Pretender’s handledRequest to execute code on each request, but be warned that Mirage relies on it for logging.
  • Add records “live” in the background with e.g. setInterval(() => server.create('record'), 25000);
  • Deploy your demo build within your development build: ember build && DEMO_MODE=1 ember build --output-path dist/demo
  • Use window.navigator.onLine to approximate whether the app is online, in order to handle special cases around other network dependencies.
  • Create an electron app!

Try it Out!

I encourage you to try mirage in your Ember project, even if you have no need for an offline demo. It makes a pretty great development API. The documentation is good, the maintainer is responsive, and the slack channel (#ec-mirage on the Ember Community Slack) has been very helpful.