Using The APP_INITIALIZER Token To Bootstrap Your Application

When it comes to running “one off” startup methods when your Angular Application starts, everyone will tell you to use the “APP_INITIALIZER” token. That’s all well and good to be told that, but when you actually check the documentation, it’s a little sparse…

Admittedly there is a bit more on the token scattered around in other documentation pieces, but they are surprisingly hard to find and again, typically only lightly touch on actual real world usage. So consider this a beginners guide on how to use APP_INITIALIZER in your own app.

The Basics

The first step is to create our startup function. For the purposes of this article, I’m going to create a simple function that itself, returns a function to run.

export function startmeup()
{
  return () => console.log('Started!');
}

It’s important that the function itself returns a function!

In our main module (typically AppModule), we want to add a provider to our NGModule decorator. For example :

@NgModule({
  declarations: [
  ],
  imports: [
  ],
  providers: [
    { provide : APP_INITIALIZER, multi : true, useFactory : startmeup}
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Ignore the fact I don’t have any declarations, I’ve removed them so it doesn’t clutter things up. Now a couple of things to note here.

  • We are adding a provider with the key of APP_INITIALIZER
  • We are setting the “multi” flag to true as we may have multiple APP_INITIALIZER’s to run.
  • And finally we are telling it to use the startmeup method to create the method we want to run.

Running our application now, we should see a console message of “Started!” as soon as the page loads.

UseValue vs Use Factory

It may look strange for our startup method to itself return a method. It seems a bit silly to box things up like that. Why not just run the startup code itself? Well you can do that (With some caveats).

For example, we could change our startmeup function to look like so :

export function startmeup()
{
  console.log('Started!');
}

Then we can change our provider line to “useValue” instead of “useFactory”

{ provide : APP_INITIALIZER, multi : true, useValue : startmeup }

The main problem you run into with this method is that it’s much harder to use dependencies. We’ll talk about that a little later on. For now, just know you can do either but there are certainly pros and cons for each. Typically I find factories provide me the most versatility.

Inline Methods

It’s obviously worth noting that you don’t need to create an entirely new function variable/object, and you can instead do it all inline.

For the useValue route, you can use :

{ provide : APP_INITIALIZER, multi : true, useValue : () => { console.log('Started!'); }}

To do the same thing with factories does look a little messier because you need to return a method that returns a method… So the nesting can look a bit extreme but in general it looks like :

{ provide : APP_INITIALIZER, multi : true, useFactory : () => { return () => console.log('Started!'); }},

Using Dependencies

It’s possible, but unlikely, that your startup method can run on it’s own with no dependencies. But it’s probably a whole lot more likely that you are going to require either outside services of your own, or Angular’s own helper services. HttpClient for example.

You can inject these into your startup factories. Note that you cannot (easily) inject dependencies when using useValue. Your application won’t blow up, but your dependency will be undefined. There are ways around this but it’s the primary reason to stick with useFactory.

As an example of using dependencies, I can rewrite my startup factory like so :

export function startmeup(http : HttpClient)
{
  return () => 
  {
    console.log(http);
    console.log('Started!');
  }
}

And I can modify my provider line adding in the “deps” field :

{ provide : APP_INITIALIZER, multi : true, deps : [HttpClient], useFactory : startmeup}

This allows Angular’s built in DI to inject in HttpClient to my startup method which is extremely handy!

Calling Startup Methods Of Services

So, exporting functions all over the place is sort of rough. And it’s pretty likely that we want to bootstrap an actual service (Maybe to reach out and grab configuration values etc). To do that, we can create a class that holds our startmeup factory. We also need to mark it as Injectable.

@Injectable({
  providedIn: 'root'
})
export class StartupClass
{
  constructor(private http:HttpClient)
  {

  }

  startmeup()
  {
    return () => 
    {
      console.log(this.http);
      console.log('Started!');
    }
  }
}

When adding our provider line, we now instead set our dependency to be the StartupClass (The additional dependency of HttpClient will be resolved behind the scenes when requesting the StartupClass). We still call useFactory as we still have to tell it which particular method we want to run on startup.

{ provide : APP_INITIALIZER, multi : true, deps : [StartupClass], useFactory : (startupClass : StartupClass) => startupClass.startmeup()}

Note that our method is actually still returning a function itself. This can be a bit off putting to read in this way so we can change it to instead simply run it’s startup calls :

startmeup()
{
  console.log(this.http);
  console.log('Started!');
}

And then modify the provider line to instead create a factory in of itself :

{ provide : APP_INITIALIZER, multi : true, deps : [StartupClass], useFactory : (startupClass : StartupClass) => () => startupClass.startmeup()}

Notice the additional () to create a method within the useFactory line.

Using Promises

A pretty common scenario for startup methods is reaching for configuration values. That could be from a file, local storage, a cookie etc. And it’s highly possible that these methods are async in nature. As an example below, I’ve modified my startup method to read a settings file.

startmeup()
{
    this.http.get('/assets/config/app-settings.json').subscribe(async x => 
    {
      await new Promise(resolve => setTimeout(resolve, 5000));
      console.log('Configuration loaded');
    });
}

Note that the await promise line is simply to make it “seem” like it’s taking a long time to complete it’s job. e.g. It’s a slow startup task. In a real world example this wouldn’t be there.

Let’s also go to our main app component and write an NgOnInit method that simple writes to the console log.

export class AppComponent implements OnInit{
  ngOnInit(){
    console.log('On Init');
  }
}

Now let’s pause for a second and think. If we run our app right now, what will be written to the console first? The “Configuration loaded” message or the “On Init” message. Well logic would tell us that surely our message that our configuration loaded will run first because we’ve told Angular that the startmeup method should be loaded before everything else.

Well that is wrong.

The problem is that the http get method returns an observable to tell us when it’s complete. And we aren’t waiting for that to finish at all.

The general pattern is to use promises and return that promise to the APP_INITIALIZER. So as an example :

startmeup()
{
    return this.http.get('/assets/config/app-settings.json').toPromise().then(async x => 
    {
      await new Promise(resolve => setTimeout(resolve, 5000));
      console.log('Configuration loaded');
    });
}

Here we are returning a promise from our method. The App Initializer will actually wait until this promise is resolved before continuing on. If we refresh our page now, we will notice that not only does the “On Init” message come after the “Configuration loaded” message. But the page itself is blank for 5 seconds (Because of our fake sleep to emulate a long http call) because all progress is halted until startup is complete.

This may sound bogus to halt an application like this. But the general idea is that the “majority” of work from your Angular application would not actually be able to take place until the startup method is resolved. For example if you are using telemetry like New Relic, Raygun, Application Insights etc. You really should have the token loaded and App Insights running before attempting to do other work. Otherwise if your application crashes, there is now a race condition as to whether you have all the necessary information to log the error or not.

Usage Outside Of Single Page Apps

As we saw above, the use of APP_INITIALIZER essentially halts the loading of a page until complete. In a true Single Page App (SPA), this is fine because it’s only really going to happen once on the initial load. If you are making use of Angular’s router for instance, then the App Initializer won’t be called again until a proper browser refresh occurs.

Obviously this isn’t the case if you are doing full page reloads. Every page load will re-load the angular app, and therefore kick off the startup process again. Be wary of using the APP_INITIALIZER token in these situations as it can severely slow down your application on every single page load.

2 comments

  1. Thanks for fantastic article.

    How to use the configuration values in App module itself (for other modules) which we get using APP_INITIALIZER? I tried the code above. The application fails to load before APP_INITIALIZER returns the configuration value.

    1. Hi Antony,

      Are you able to create a small Git repo/gist with your code? If your application is failing to load *before* your app initializer runs, then it can be one of two things. Your App Initializer is not returning a promise so it can’t be awaited *OR* reading between the lines on what you are saying, I have had to sometimes create a “StartupService” and make that the *only* app initializer I use, and then make that startup service call everything else in the order I need it. I do remember on a couple of projects really having big issues when I had multiple app initializers that need to run in specific orders etc. And creating a single startup service was how I solved it.

Leave a Reply

Your email address will not be published. Required fields are marked *