Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Angular 17 Standalone: app.config.ts or main.ts?

Confused about Angular 17 standalone setup? Learn whether to use app.config.ts or main.ts for routing and providers.
Angular 17 main.ts vs app.config.ts futuristic coding interface with electric face-off Angular 17 main.ts vs app.config.ts futuristic coding interface with electric face-off
  • Angular 17 standalone components make apps load up to 15% faster.
  • NgModules are now not needed, which makes app structure and managing dependencies simpler.
  • main.ts now only starts the app with less setup code.
  • app.config.ts handles routing and provider setup, which helps apps grow.
  • Testing is now more separate and quicker with standalone APIs in Angular 17.

Angular 17 brings a new, modular way to build Angular applications. It moves away from NgModules, which were once very important. Instead, it uses standalone components and simpler configurations. Because of this change, developers are asking where to put things like routes, services, and global settings. Should they stay in main.ts or go to app.config.ts? In this guide, we will explain what each part does. We will also offer good ways to set up a modern Angular app. This will help you switch over and grow your app easily.


The Shift to Angular 17 Standalone Components

Angular has gotten much more modern with version 17. It puts standalone components, directives, and pipes at the heart of how apps are built. With standalone APIs, developers can build features and views without putting them inside NgModules. This means fewer files, simpler imports, and developers find it easier to use.

Developers have wanted standalone features for a long time, and now they have them. Angular developers often said NgModules created too much extra work. They noted the extra setup code and how it made things unclear, especially in smaller apps. Now, you can write full Angular apps without using any NgModule.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Standalone components are defined like this:

import { Component } from '@angular/core';

@Component({
  selector: 'app-my-feature',
  standalone: true,
  templateUrl: './my-feature.component.html',
  styleUrls: ['./my-feature.component.css']
})
export class MyFeatureComponent {}

This simple way of declaring components greatly reduces how complex NgModule imports, declarations, and exports used to be.

Why Angular’s Modular Architecture Is Changing

In the past, NgModules grouped related components, directives, and services together. But this made sense early on. Now, with many large apps and new ways of building apps, some problems have appeared:

  • Complex Dependencies: NgModules link components and services in ways that are not always clear. This makes it hard to see how things depend on each other.
  • Testing is More Complex: Reusable modules often needed a lot of fake data (mocking) when tested with TestBed.
  • Too much work for Small Features: Even a simple button or dialog might have needed extra module setup.

With standalone APIs:

  • Components say they are standalone: true, meaning they work on their own.
  • Tree-shaking—where unused code is taken out of the final app builds—works much better.
  • Routing is now clearer and more separate.

This change fits with Angular’s plan to be more modular and perform better. Google said at their 2023 I/O conference that standalone APIs make app sizes 10–15% smaller and make pages load much faster at first [(Google I/O, 2023)].

Understanding Angular main.ts Setup in Version 17

In older Angular, main.ts looked like this:

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

But with Angular 17 standalone apps, main.ts starts the main component directly instead:

import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';

bootstrapApplication(AppComponent, appConfig)
  .catch(err => console.error(err));

What main.ts Now Handles

  • Bootstrapping: It starts your app by calling bootstrapApplication.
  • Global Setup: It can set up services that work across the whole platform, like for logging or environments.
  • Delegation: It gets more providers from app.config.ts.

This way, main.ts stays short. Think of it as where your app begins. There's no complex code here, just starting things up.

What Goes in app.config.ts?

The app.config.ts file holds your app's main settings. It sets up Angular services like routing, HTTP clients, interceptors, and others.

Here’s a typical setup:

import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { routes } from './app/app.routes';
import { APP_INTERCEPTORS } from './core/interceptors';

export const appConfig = {
  providers: [
    provideRouter(routes),
    provideHttpClient(withInterceptors(APP_INTERCEPTORS))
  ]
};

Responsibilities of app.config.ts

  • Routing: It uses provideRouter() to set up routing for the whole app.
  • HTTP Setup: It adds HttpClient and can set up interceptors.
  • Service Providers: It puts reusable services or services that work across the whole platform in one place.
  • Can be easily swapped: You can break it into smaller parts and replace it completely for testing or different builds.

You can also use importProvidersFrom() to bring in older modules or services from other companies.

main.ts vs app.config.ts: Who Handles What?

To reduce confusion, here’s a full breakdown:

Functionality main.ts app.config.ts
Bootstrapping application
Reading environment variables
Tracking feature flags at startup
Defining routing with provideRouter()
Registering HTTP clients/interceptors
Consolidating third-party providers ✅ (if critical to boot) ✅ (if app-level config)
App-level configuration 👌 Minimal ✅ Preferred

Keep these parts separate. This helps keep your app neat and able to grow.

Migrating from NgModules to Standalone: Step-by-Step

Moving over might seem scary. But Angular has made it easier than you might think.

Step 1: Identify NgModules to Remove

First, find NgModules that are not needed, especially those for specific features. If a module only has one component or just handles routing, you can likely remove it.

Step 2: Convert Components to Standalone

Change the component’s decorator:

@Component({
  standalone: true,
  ...
})

Also, change any directives or pipes to standalone if you use them a lot in different features.

Step 3: Move Routes

If you used RouterModule.forRoot() or forChild() for features, move them to app.routes.ts and export them as routes. Then, register them using provideRouter(routes) in app.config.ts.

Step 4: Refactor Services

Use provideHttpClient() and your own provider lists to replace @NgModule.providers.

Step 5: Update main.ts

Last, call bootstrapApplication() with your main component and settings.

If you do this right, you will make things simpler and build an app that will work well in the future.

Routing in Angular 17 Standalone Apps

Routing is now clearer and easier to put together in Angular 17. The new provideRouter() API removes a lot of the repeated code that module-based Angular apps used to need.

export const routes: Routes = [
  { path: '', component: HomeComponent },
  {
    path: 'dashboard',
    loadChildren: () => import('./features/dashboard/dashboard.routes')
      .then(m => m.routes)
  }
];

This allows:

  • Lazy Loading: Modules only load when they are needed.
  • Tree-Shakable Routes: Unused paths are removed from the final app builds.
  • Modular Route Files: You can keep route files with their feature folders.

Best Practices for Angular Provider Injection

Angular’s provide* APIs make adding services cleaner. And importProvidersFrom() helps bring in existing service setups.

Use it this way:

import { HttpClientModule } from '@angular/common/http';
import { importProvidersFrom } from '@angular/core';

export const appConfig = {
  providers: [
    importProvidersFrom(HttpClientModule)
  ]
};

🔑 Key Tips:

  • Use provideHttpClient() for new code.
  • Use importProvidersFrom() to keep things compatible.
  • Do not mix these methods in the same part of your project.

When Should Logic Stay in main.ts?

Some things are best done in main.ts:

  • Startup Setup: Reading cookies, session storage, or setting up the environment on the fly.
  • Feature Flags: Turn on or off starting logic based on user flags.
  • Important Monitoring: For example, logging or analytics that need to start collecting data early.

Generally, if something is only needed when the app starts, keep it in main.ts.

Suggested Project Structure for Standalone Angular

Here is a good folder layout:

src/
├── main.ts
├── environments/
├── app/
│   ├── app.component.ts
│   ├── app.config.ts
│   ├── app.routes.ts
│   ├── core/
│   │   ├── interceptors/
│   │   ├── services/
│   ├── features/
│   │   ├── dashboard/
│   │   └── user-profile/
│   └── shared/
│       ├── components/
│       ├── directives/
│       └── pipes/

This setup focuses on:

  • Keeping different parts separate.
  • Building features in a way that allows the app to grow.
  • Reusing code in shared and core parts.

Common Errors When Moving to Standalone

Do not make these common mistakes:

  • Importing things into main.ts that need routing to work
  • Forgetting standalone: true for components that are loaded later by routes
  • Leaving NgModules that wrap components already set as standalone

Always test after each step of moving over. And watch how things depend on each other carefully.

Performance Benefits of Standalone Angular

Angular 17's standalone way of building apps is made to create faster builds and smaller app files.

Measurable Improvements

  • Load times are up to 15% faster [Google I/O, 2023].
  • App files are smaller because routers and providers can be tree-shaken.
  • Less extra work when compiling modules during unit testing.

These improvements mean a smoother user experience and lower costs for setting up servers.

Improved Testing and Maintainability

With standalone APIs:

  • Tests are easier to set up. Often, you do not need TestBed.
  • Fake services (mocks) are more precise because services are added separately.
  • End-to-end tests do not need to go through complicated module structures anymore.

A component works on its own. This makes it much easier to test and reuse.

Future-Proof Your Angular App

Angular's official plan is to move away from NgModules and build apps with components first. Using standalone now:

  • Reduces old, hard-to-manage code.
  • Makes upgrades simpler.
  • Gets your team and your CI/CD pipeline ready for where Angular is heading.

This is more than just a way of writing code. It lines up with Angular's next stage.

Summary: When to Use What

Use Case main.ts app.config.ts
Application bootstrapping
Routing configuration
Service provider injection ✅ for startup logic ✅ for general app services
Lazy loading configuration
Integrating HTTP Interceptors
Environment detection

Keep main.ts focused on its job. Let app.config.ts handle your settings as your app grows.


Ready to build the next generation of Angular apps? Build with modules, use standalone, and make your app easier to test, faster to build, and simpler to grow.


Citations

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading