Miloš Zeljko

Top 3 ways how to organize your Angular project

Miloš Zeljko
March 11, 2023 9 mins to read

Angular is a powerful web framework that provides developers with a variety of tools and features to create robust and maintainable applications. However, one of the biggest challenges that Angular developers face is structuring their applications in a way that is scalable, maintainable, and easy to understand.

In this blog post, we will look at the three best ways to structure your Angular project according to my opinion. Keep in mind that every project is unique, therefore its structure should be adjusted according to project needs. Take these examples as a base for your structuring style.

Why should I care about the structure of my Angular project?

When working with a well-structured project, finding the file you are looking for becomes much easier. That is because you know where to look to find it. For example, if you are looking for the code of a component on a particular page and you packaged your project so that every page is a module for itself, you can go to the folder of that page with ease and look for the desired component there.

Suddenly instead of searching through the whole project, you are inside an isolated module that contains all the classes that could potentially directly interact with a component you are looking for. In addition to finding the component’s code, we have all the related code right next to it!

That is the power of well structured Angular application. No matter how big our application grows, if we keep related files close to each other in a standardized way, we will have a much easier time finding what we want. Spending less time wandering around and more time thinking about our code and the problem we are solving.

Why is standardization important when it comes to Angular project structure?

The most important thing is to be consistent. No matter which structuring style you choose, stay consistent to feel the benefits of a well-structured project. The purpose of structuring your code strictly is to make navigation through the code base easier.

If you know that all components like ConfirmButtonComponent, CancelButtonComponent, AutocompleteComponent, CustomTabsComponent etc… are placed inside the UI module inside a shared directory as respective sub-modules or part of the UI module, then placing the component SubtitleLabelComponent inside a module of some page that uses it makes no sense. Naturally, after some time working on something else, you might want to reuse that component or maybe alter it. You will assume it is a part of the UI module or at least a sub-module inside.

But because you did not follow a strict structuring style, you won’t find it there. Forcing you to wander around your code base, trying to remember where have you put it. This can be difficult, especially if you forgot the correct name of the component and can’t search for it.

What structuring styles do I recommend for Angular projects?

Now that we have looked at why it is important to have a structuring style defined and to follow it strictly, let us dive into examples of well-structured Angular projects. We are going to take a look at the file structure as a whole and explain the main idea of packaging and discuss the advantages and disadvantages of each approach. Then we will focus on sub-directories and discuss how they can be altered to fit your project needs.

Here is the list of structuring styles we are going to discuss:

  1. Package by the pages
  2. Package by the pages and sub-pages
  3. Package by the features

Package by the pages

Let us take a look at the app directory. We can see it consists of 3 sub-directories: core, pages and shared.

angular project structure 1

Inside the core, we should put all singleton classes that are instantiated only once and used across our application. We can place guards, interceptors, models and services that are used throughout the whole application. Some examples of classes that would belong here would be User, AuthService, NotificationService, HasAdminRoleGuard etc… Make sure to import the core module only inside your app module and nowhere else!

angular project structure 2

Inside the pages, we should make a module for each page. What qualifies as a page? Every component with a route attached to it. Make sure to name your page modules the same as the route it is attached to. Why? Because it makes it easier to find a page by just looking at the address bar. For example, if the address bar looks like http://localhost:4200/page-one, we know that module containing all components on that page is probably inside the pages directory as a page-one sub-directory.

angular project structure 3

What I like to do is to name my pages as *.page.ts instead of *.component.ts to make it clear that this component has a route attached to it. This is also the case with dialogs, which represent a component that is being displayed inside MatDialog from Angular Material. So by naming it *.dialog.ts it makes it easier to conclude what it represents.

You don’t have to follow this pattern, you can create your component types as you see fit. This is what works best for me. It is completely fine to keep the *.component.ts name for everything.

With each page as a separate module, they can have components, dialogs, services or even other pages as sub-pages on a path that looks like this: /page-one/sub-page. Here a sub-page would be a module inside the page-one module. For the components and the dialogs directory, we would place all unique components in your application that are present only on this page and nowhere else. Same with the services, if we have a service that is going to be used on this page only, it makes sense to place it inside this module.

Every sub-page can have its components, dialogs, services etc. It will be mostly independent of the root page, but as it shares the path with it, it is placed inside the root page to make it easier to find. This can create a lot of nesting and depth in your project structure which can be potentially bad. It can be good when there are a lot of pages, to keep them more separated, but when the number of pages isn’t that big then a second approach would be better. Where we package by pages and sub-pages.

Third and the last directory, shared, is a place where you can put all modules, components, dialogs, directives, pipes, models etc… that are used by multiple pages or don’t belong to any particular one. These classes should be exported and be available to use inside other modules that need them. An example of what could go here would be a UIModule, which consists of multiple sub-modules, like ButtonModule, SearchModule, AutocompleteModule, InputModule etc. So anything that could be reused on more than one page should be here, inside the shared module. When importing classes from the shared module, do not import them directly inside AppModule, rather import them in the page module it will be used in.

angular project structure 4

The advantage of packaging by pages is that we can do lazy loading of our page modules when we enter a certain path instead of loading everything at the start. To achieve this we can define routes this way in app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
    { path: '', loadChildren: () => import('./pages/home/home.module').then(m => m.HomeModule) },
    { path: 'page-one', loadChildren: () => import('./pages/page-one/page-one.module').then(m => m.PageOneModule) },
    { path: 'page-two', loadChildren: () => import('./pages/page-two/page-two.module').then(m => m.PageTwoModule) }, 

  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
export class AppRoutingModule { }

Package by the pages and sub-pages

This approach is almost identical to the first one, where we package by pages. The only difference is that we don’t have sub-pages inside pages. Instead, we place all pages as separate modules in the pages directory. This way we eliminate deep nesting in our project structure. To make pages easier to find, we can group them in directories with root page names. For example, inside pages, we can have a page-one directory that would contain PageOneModule and all other sub-page modules as separate sub-directories in the page-one directory.

angular project structure 5

The rest of the structure is the same as the first approach, each page now has its components, services, modules…

Package by the features

In this approach, we put focus on features instead of pages. A feature is a unit of the functionality of the software that allows users to perform the action and interact with the system. An example would be the posts feature. It would include all classes that are responsible for manipulating posts, like CreatePostDialog, PostListComponent, PostService etc…

Each feature module can contain multiple pages that are being used to display feature functionality to the user. We package everything under three directories again. But this time instead of pages, we have features or modules directory. You can call it however you like, I prefer to name it modules. The other two directories, core and shared are the same as in the previous two examples so we won’t go into detail about them again.

angular project structure 6

We will focus on the modules directory where we can spot the difference. Every feature will have its components, services, dialogs, modules, models etc… that are used only inside it. The advantage of this approach over the first and second is that we have a bigger module that encapsulates everything related to a certain feature or feature set. Instead of having everything separated by the pages, we have all classes that rely on each other placed together.

This approach is great when working with microservices or when following DDD (Domain Driven Design) on a backend, as each microservice or bounded context we work with, can be represented as a feature on our Angular application and therefore placed into a separate module with its ubiquitous language.

Hopefully, you learned something new. What project structure do you use and what works best for you? Tell me in the comments. Also if you have any suggestions on how to improve the project structures we have discussed in this blog, don’t hesitate to leave them in the comment section.

Leave a comment

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