Technology Blog

Look deep into latest news and innovations happening in the Tech industry with our highly informational blog.

How to structure Angular Apps


There are many ways one can structure an Angular app. But this is how we structure our applications for extensive flexibility, scalability, and small initial bundle size.

Fig-1: Preferred Directory Structure
Pic courtesy:

  • Core: The things that are absolutely essential for the app to start.
  • Features: Business logic. Contains modules, components, services, and other angular building blocks (if required) for a particular business feature.
  • Shared: Components so dumb that it hurts!
  • Pages: Routed components with lazy loaded modules.


Core directory is the place where you put singleton services, injection tokens, constants, app configurations, pipes, interceptors, guards, auth service, utils, etc. that will be used app-wide. If there is something which is specific to the application itself, deployment, CI/CD, API, and the Developer – chances are, it belongs to the core.

Fig-1: Example Core directory
Pic courtesy:


Business features live in this directory. Make a module per feature. That module can contain components, directives, pipes, services, interfaces, enums, utils, and so on. The idea is to keep things close. So, a pipe, that is solely used in the Speakers module should not be defined in the global scope or inside Core. The same goes for any other angular building block required by this module only.

Fig-2: An example feature module
Pic courtesy:

Components are prefixed according to the module name e.g.- if the module name is SpeakersModule, components would be named SpeakerAbcComponent, SpeakerXyzComponent etc.

Keep the component tree inside the directory flat. That means, if SpeakerListComponent is the parent and SpeakerListItemComponent is child, do not create speaker-list-item component inside the speaker-list directory. The prefixed naming should be clear to indicate such a relation. The idea is to be able to see what components reside in the module at a glance.

Feature modules can import other features and obviously from shared modules.


Consider shared modules a minWe library for your UWe components. They are not specific to a single business feature. They should be super dumb that you can take all the components, drop in another angular project, and expect to work (given the dependencies are met). You might already know that wrapping UWe components provided by other libraries such as Material, ng-zorro-antd, ngx-bootstrap, etc. is a good practice. It protects you from their APWe changes and allows you to replace the underlying library if required. Components in shared modules are a good place for such wrapping.

Fig-3: Example Shared Directory
Pic courtesy:

Do not make a giant SharedModule, rather granularize each atomic feature into its own module (see Fig-3). Criss-cross import of atomic shared modules is allowed, but try to minimize as best as possible. To bring a flavor of a tiny library, you could even prefix the directories & modules with your angular application’s custom prefix (by default it is app ).


Pages directory is the most interesting part of this structure. Think of it like a sink, where feature modules fall into but nothing comes out (i.e- no exported member). In these modules, you do not declare any component other than the page.

Fig-4: Example Page Module
Pic courtesy:

Page controllers have no business logic. They are merely the presenter and orchestrates components from business feature modules. Let’s say – home page. It will contain a header, a hero section, articles, comments, contact, etc. sections – all coming from respective feature modules!

    declarations: [HomePageComponent],
    imports: [
export class HomePageModule {}

How a fictional home-page.component.ts might look like:

<main class="container">

They can take help from a page-specific service that combines data and state for that page only. You should provide such service to the page component and NOT in root. Otherwise, the state may persist even after you navigate away from the page because the page component will get destroyed but not the page service.

// home-page.service.ts
export class HomePageService {}

// home-page.component.ts
    providers: [HomePageService]
export class HomePageComponent {
    constructor(private homePageService: HomePageService){}

The most important purpose of page modules is that each module is loaded lazily to make the app performant and lite.

Every page module is lazy-loaded!

Pro-tip: If you define a single page component per module, then you can claim a further reduction in the initial bundle size. This practice also organizes all routes in a single source (namely AppRoutingModule) which is easier to manage. Then, your app-routing.module.ts file may look like this:

const appRoutes: Routes = [
        path: '',
        loadChildren: () => import('./pages/home-page/home-page.module').then((m) => m.HomePageModule),
        path: 'home',
        redirectTo: '',
        pathMatch: 'full',
        path: 'products/:id',  // <-------- NOTE 1. Child route
        loadChildren: () =>
            import('./pages/product-details-page/product-details-page.module').then((m) => m.ProductDetailsPageModule),
        path: 'products',     // <--------- NOTE 2. Parent route
        loadChildren: () =>
            import('./pages/product-list-page/product-list-page.module').then((m) => m.ProductListPageModule),
        path: 'checkout/pay',
        loadChildren: () =>
            import('./pages/checkout-payment-page/checkout-payment-page.module').then((m) => m.CheckoutPaymentPageModule),
        path: 'checkout',
        loadChildren: () => import('./pages/checkout-page/checkout-page.module').then((m) => m.CheckoutPageModule),
        path: '**',
        loadChildren: () => import('./pages/not-found-page/not-found-page.module').then((m) => m.NotFoundPageModule),

Notes 1 & 2: Since route declarations are parsed top-to-bottom, be sure to declare child paths before the parent path. This will ensure lazy-loading chunks fetched correctly. Otherwise, if you define the parent route first, then visiting any child route will also load the parent route’s module chunk unnecessarily. You can see the difference in DevTools. Here is my experiment when We put parent route first (Fig-5.1) VS child route first (Fig-5.2)

Fig-5.1: When /products declared BEFORE /products/:id in routes config
Pic courtesy:

Fig-5.2: When /products declared AFTER /products/:id in routes config
Pic courtesy:

For more information and to develop web application using Angular, Hire Angular Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – or Skype us: “hkinfosoft”. To develop web application using Angular, please visit our technology page.

Content Source: