My Angular Best Practices

Angular application can be very complex: getting lost between services and components is easy when the application grows and many people are working on it. Here’s a short list of my best practices to create fast and well organized applications.


Modules are meant to split your app into many smaller bundles, but sometimes it’s quite confusing to know where I should declare a component.

IMHO there are some basic modules you can start from:

  1. SHARED MODULE: create a shared module and use it for the common parts of the application: pipes, common components (header, footer, newsletter, etc..), directives and everything you may need in more than one page.
  2. ROUTE MODULES: create a module for every route, even if the route is made up by a single component. This will allow to lazy load the code only when you navigate to that route (see point 2).
  3. API MODULE: if you need to interact with a backend it’s better to have all the services, classes and interfaces in the same place. Provide this module only on app.module and don’t forget to add providedIn decorator.

When you create a new component you should ask:

Where I’ll use it?
If I need it in more than one page of the app (example: a newsletter subscribe form), place it in the shared module, if, instead, I’ll need it only on a single route (example: a result from a search), place it in that route’s module.


Complex applications are HUGE! You may think that 1 megabyte of data isn’t really much to download, but do never forget that your users may be using a mobile device with poor connection.

Setting up angular router to lazy load modules will create smaller bundles reducing the amount of code transferred before bootstrapping the application, making it much faster.

I will soon write something about this topic, meanwhile, you can read about this practice in the official documentation.


Observables are great but can be tricky and can lead to weird bugs when you forget to unsubscribe them. A simple rule I’ve learned is:

Use the async pipe! Do not subscribe into the component class.

Async pipe will automatically unsubscribe when the component is destroyed, so you don’t have to do it manually.

There are some nice tricks you can do with observables and the async pipe, again, I’ll write an article about it soon, I promise 😉


This is something easy to forget.

When the contents of a component won’t change, set change detection strategy to OnPush.

It takes a single line in the component decorator:

    selector: 'app-my-component', 
    templateUrl: './my.component.html', 
    changeDetection: ChangeDetectionStrategy.OnPush 
export class MyComponent { ... }

By default Angular will check EVERY COMPONENT when anything changes in the app. No need to explain that this can be a long and slow task for your browser.

OnPush will instruct Angular to watch for changes only when an input changes its reference (note: reference, not value!) or when you explicitly tell angular to do it.

You can read more about this in the docs.

5. USE NgRx (with moderation)

NgRx is a great tool, but do not overuse it.

Always focus on what you are doing: if you just need to fetch some data from an API and display it, then NgRx is a waste of code: a simple http call and an async pipe would do the same.

If you have to execute some actions on a set of data, like filtering some search results, or you must spread info between many components, like the authenticated user, than NgRx is a good choice.

I know that mixing NgRx and plain API calls may not sound like a good idea from adeveloper point of view, but I also believe that a faster app is better than an app with optimal code.


Accessing your browser’s window or document objects is very tempting, but do not forget about Server Side Rendering! In an SSR environment there is no document or window, or any other browser related global object.

You may not be planning to use Angular Universal, but, if you will change your mind later,your code will be ready for it.

If you really need the document, then remember that Angular offers an injectable abstraction of it: See DOCUMENT on the api docs.