---
# System prepended metadata

title: Ways to bootstrap an application

---

# Ways to bootstrap an application

##  Approach 1 (Abandoned)
### main.ts

```ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppRoot } from './app';
import { providers } from './config';

const bootstrap = () =>
  bootstrapApplication(AppRoot,  { providers }));

if (document.readyState === 'complete') {
 await bootstrap().catch(err => console.error(err);
} else {
 document.addEventListener('DOMContentLoaded',
     () => bootstrap().catch(err => console.error(err));
}
```

### main-server.ts
```ts!
import { bootstrapApplication } from '@angular/platform-browser'; // It's akward that the server depends on the browser module
import { AppRoot } from './app';
import { providers } from './config';


export default bootstrapApplication(AppRoot, {
  providers: [
    ...providers,
    provideServerModule(),
    provideRouter(ROUTES),
    ...
  ],
});
```

## Approach 2 (Abandoned)

### main.ts
```ts
import { bootstrapApplication } from '@angular/platform-browser';

import { AppRoot } from './app';
import { config } from './config';

const bootstrap = (extraConfig: ApplicationConfig) =>
  bootstrapApplication(AppRoot, deepMerge(config, extraConfig)));

if (document.readyState === 'complete') {
 await bootstrap().catch(err => console.error(err);
} else {
 document.addEventListener('DOMContentLoaded',
     () => bootstrap().catch(err => console.error(err));
}

export default bootstrap;
```

### main-server.ts
```ts
import { provideServerModule } from '@angular/platform-server';

import bootstrap from './main';

export default bootstrap({
  providers: [
    provideServerModule(),
    provideRouter(ROUTES),
  ]
});
```

## Approach 3 (Abandoned)

### main.ts
```ts
import { bootstrapApplication } from '@angular/platform-browser';

import { AppRoot } from './app';
import { config } from './config';

const bootstrap = (appConfig: ApplicationConfig = config) =>
  bootstrapApplication(AppRoot, appConfig);

if (document.readyState === 'complete') {
 await bootstrap().catch(err => console.error(err));
} else {
 document.addEventListener('DOMContentLoaded',
     () => bootstrap().catch(err => console.error(err)));
}

export default bootstrap;
```

### main-server.ts
```ts
import { provideServerModule } from '@angular/platform-server';

import { config } from './config';
import bootstrapApp from './main';

const bootstrap = (extraConfig: ApplicationConfig) =>
  bootstrapApp(
    AppRoot,
    deepMerge(
      config,
      {
        providers: [
          provideServerModule(),
          provideRouter(ROUTES),
        ],
      },
      extraConfig,
    ),
  );
  
export default bootstrap;
```

## Approach 4 (Abandoned)

`bootstrapApplication` code is generated internally in the CLI for both the client and server bundles. This is something that came too mind that I wanted to share. I personally do not think I'd go for this as it can feel too magical and might be harder to debug bootstrapping issues.

### main.ts
```ts
import { AppRoot } from './app';
import { config } from './config';

const bootstrapAppConfig = {
    component: AppRoot,
    applicationConfig: config,
};

export default bootstrapAppConfig;
```

### main-server.ts
```ts
import browserConfig from './main';

const serverConfig = {
  providers: [
    provideServerModule(),
    provideRouter(ROUTES),
  ],
};

const bootstrapAppConfig = [browserConfig, serverConfig];

export default bootstrapAppConfig;
```


## New Approches Intro

Potentially by default we might not even need to create the main-server file. 

Given that: 
* `provideServerModule` is added as a platform provider when rendering SSR/SSG. Maybe though this would cause more complexity for users when trying to figure out how to add a provider for server?
* `withServerTransition` becomes redundant following https://github.com/angular/angular/pull/48253
* Handle app-shell completly differently. Currently app-shell is just another root on the server. Following some explorations I feel that we can just avoid adding additional routes instead just bootstrap the application using `AppShell` instead of `AppRoot` as component. This comes with a drawback of 1 extra file, but removed the need of having server specific routing. 
    

## Approach 5 (New)

### main.ts
```ts
import { Providers } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';

import { AppRoot } from './app';
import { config } from './config';

const bootstrap = (extraProviders: Providers[]|undefined, rootComponent = AppRoot) => 
    bootstrapApplication(rootComponent, { 
        ...config,
        providers: [
            ...config.providers
            ...extraProviders,
        ]
    });

// Should `bootstrap()` be done by the CLI or not?
// await bootstrap();

export default bootstrap;
```

### main-server.ts
```ts

import { Providers } from "@angular/core";
import { provideServerModule } from "@angular/platform-server";

import bootstrapApp from "./main";

const bootstrap = (extraProviders: Providers[] = []) =>
  bootstrapApp([
    provideServerModule(),
    ...extraProviders,
  ]);

export default bootstrap;
```

    
### app-shell.ts
```ts
import { Providers } from "@angular/core";
import { provideServerModule } from "@angular/platform-server";

import bootstrapApp from "./main";

const bootstrap = (extraProviders: Providers[] = []) =>
  bootstrapApp([
    provideServerModule(),
    ...extraProviders,
  ], AppShell);
  
export default bootstrap;
```

## Approach 6 (New)

Maybe we are trying to over thinking it and the simplest would to use `bootstrapApplication` directly.

### browser.ts
```ts
import { bootstrapApplication } from '@angular/platform-browser';

import { AppRoot } from './app';
import { config } from './config';

const bootstrap = () => bootstrapApplication(AppRoot, config);

// Should `bootstrap()` be done by the CLI or not?
// await bootstrap();

export default bootstrap;
```

### server.ts
```ts
// This is a bit odd that server depends on platform-browser
// Maybe @angular/platform-server could have a bootstrapApplication that already provides the `ServerModule`?
import { bootstrapApplication } from '@angular/platform-browser'; 

import { AppRoot } from './app';
import { config } from './config';

const bootstrap = () => bootstrapApplication(AppRoot,  { 
  ...config,
  providers: [
      ...config.providers,
      provideServerModule(),
  ]
});

export default bootstrap;
```


### app-shell.ts
```ts
import { bootstrapApplication } from '@angular/platform-browser';

import { AppShell } from './app-shell';
import { config } from './config';

const bootstrap = () => bootstrapApplication(AppShell,  { 
  ...config,
  providers: [
      ...config.providers,
      provideServerModule(),
  ]
});

export default bootstrap;
```



## Approach 7 (New)


### main.ts
```ts!
import { bootstrapApplication } from '@angular/platform-browser';
import { App } from './app';
import CONFIG from './app.config';

const bootstrap = () => bootstrapApplication(App, CONFIG);

export default bootstrap;
```

### main.server.ts 
```ts!
import { mergeConfig } from '@angular/platform-browser';
import { bootstrapApplication } from '@angular/platform-server';
import { App } from './app';
import CONFIG from './app.config';

// By default we don't need to add overrides.
// This is because bootstrapApplication provides the ServerModule.
// We might not even need to provide a mergeConfig in this case.
const SERVER_CONFIG = {};

const bootstrap = () =>
  bootstrapApplication(App, mergeConfig(SERVER_CONFIG, CONFIG));

export default bootstrap;
```

When using an app-shell the `SERVER_CONFIG` will be updated to:
```ts!
// For the app-shell use-case we just add an additional route.
// This is the same as `providerRoute([{ ... }])` which is deprecated.

const SERVER_CONFIG = {
  providers: [{
    provide: ROUTES,
    multi: true,
    useValue: [
      {
        path: 'shell',
        component: AppShellComponent
      },
    ],
  }],
};
```

## Questions
* Do we need to expose a way for users to override/set `platformProviders`? My 2 cents is no.
* What are the cases that we need different routes on client and server? Currently there is only one case which is for the app-shell.
* Should we internally call `renderApplication` from the exported `bootstrapApplication`?
* Can we add additional providers after bootstrapping but before rendering such as `ɵSERVER_CONTEXT`, `INITIAL_CONFIG` etc? (If not probably Approach 3 would be needed to provide providers from the CLI/Universal
* Benefits of app-shell as a route vs bootstrapped component.