This content originally appeared on DEV Community and was authored by Dan Bui
Building a robust, maintainable, and scalable front-end application isnβt easy; many things have to be done. Well structure is one of the most important parts. In this post, I will share my preferred Angular structure with the Nx workspace
Prerequisite
- Angular 17
- Nx workspace
What is Nx?
In recent years, Nx workspace has become the most popular tool for building and managing applications. Nx is an open-source, technology-agnostic build platform designed to efficiently manage codebase of any scale. Nx understands our project relationship and dependencies, executes tasks smarter and faster!
Group
First of all, I separate the app into three main groups:
- Core - singleton services or other parts that should import only one when the application is instantiated
- Shared - Components or other parts that are shared entire our application
- Feature - Smart components that map one-to-one with our business
Each part of the group has a prefix that corresponds to the groupβs name. For instance, core-service, shared-button-ui, feature-product-list. As my style, I like a flat folder over a nested folder π.( nested folder style we structure like this: core/services shared/button-ui )
App Structure
After identifying which group we should put into. We have the structure below:
βββ apps
β βββ my-app
βββ libs
βββ core-api
βββ core-guard
βββ core-interceptor
βββ core-layout
βββ core-service
βββ customer
β βββ feature-detail
β βββ feature-list
βββ shared-button-ui
βββ shared-hover-directive
βββ shared-percent-pipe
βββ shared-upper-case-pipe
Let's explain from top to bottom
Core-service
Type: lib (folder)
Tag: type: core
- Services which we intend to keep as a singleton, such as user-service,theme-service, often @injectable({provideIn:βrootβ})
Tip
Prevent CoreModule from being imported twice:
import { NgModule, Optional, SkipSelf } from '@angular/core';
@NgModule({
// declarations, imports, exports, etc.
})
export class CoreModule {
// This is the constructor guard
constructor(@Optional() @SkipSelf() parentModule?: CoreModule) {
if (parentModule) {
throw new Error(
'CoreModule has already been loaded. Import it only in the AppModule.'
);
}
}
}
Core-guard
Type: lib (folder)
Tag: type: core
- Guards we apply across our application, such as role-guard, auth-guard
Core-interceptor
Type: lib (folder)
Tag: type: core
- Interceptors we apply in our application, such as response-interceptor, error-interceptor
Core-api
Tag: type: core
Type: lib (folder)
- Api service which interacts with our back-end system, such as product-api,order-api, often @injectable({provideIn:βrootβ})
Core-layout
Tag: type: core
Type: lib (folder)
- Including all layouts which is loaded at the initial page load and loading only one, such as app-header, app-layout, app-footer
Shared-ui-[componet-name]
Tag: type: ui
Type: lib (folder)
- Components that we intend to share across our application. Keep it dump as much as possible, such as shared-ui-button, shared-ui-dropdown.
Shared-directive-[directive-name]
Tag: type: directive
Type: lib (folder)
- Directives which we intend to share across our application, such as shared-directive-hover, shared-directive-double-click, keep it separate, avoid putting it together
Shared-pipe-[pipe-name]
Tag: type: pipe
Type: lib (folder)
- Pipes which we intend to share across our application, such as shared-pipe-percent, shared-pipe-upper-case, keep it separate, avoid putting it together
Feature-[feature-name]
Tag: type: feature
Type: lib (folder)
I strictly follow the DDD (Domain Driven Development) approach. There are 2 dimensions:
-
Horizontal: Each domain business has sub-domains/features. For instance, a customer domain has sub-domains/features: customer-profile, customer-list, customer-order. We have the structure below:
βββ apps β βββ my-app βββ libs βββ customer β βββ feature-detail β βββ feature-list -
Vertical: Inside each domain/sub-domains involves these parts:
- pipe
- directive
- service
- component
- constant
- helper
feature-name/ βββ constant/ // For feature-specific constants or enums βββ directive/ βββ helper/ // For utility classes or pure functions βββ pipe/ βββ service/ βββ feature-name.component.ts // The main component
These ones are used internally or shared with sub-domains
Conclusion
Above, I shared my preferred Angular structure with Nx. Well-structured code is the βkeyβ for building maintainable, scalable applications. In the next post, I will share my boundaries setup (Nx workspace). If you have another viewpoint or adjustment, feel free to drop a comment.
This content originally appeared on DEV Community and was authored by Dan Bui
Dan Bui | Sciencx (2025-10-23T04:15:09+00:00) Structure Angular app with Nx workspace. Retrieved from https://www.scien.cx/2025/10/23/structure-angular-app-with-nx-workspace/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.