Building and Testing Angular Apps in Nx
This tutorial walks you through creating an Angular monorepo with Nx. You'll build a small example application to understand the core concepts and workflows.
What you'll learn:
- How to structure multiple Angular apps and libraries in a single repository
- How Nx's caching speeds up your local development and CI pipelines
- How to run builds, tests, and serve commands efficiently across multiple projects
- How to share UI components and utilities between Angular applications
- How to fix CI failures directly from your editor with Nx Cloud
Prerequisite: Tutorial Setup
Section titled “Prerequisite: Tutorial Setup”This tutorial requires aGitHub account to demonstrate the full value ofNx - including task running, caching, and CI integration.
Step 1: Creating a new Nx Angular workspace
Section titled “Step 1: Creating a new Nx Angular workspace”Let'screate your workspace with our Angular preset to get started quickly.
Step 2: Verify Your Setup
Section titled “Step 2: Verify Your Setup”Please verify closely that you have the following setup:
- A new Nx workspace on your local machine
- A corresponding GitHub repository for the workspace with a
.github/workflows/ci.yml
pipeline preconfigured - You completed the full Nx Cloud onboarding and you now have a Nx Cloud dashboard that is connected to your example repository on GitHub.
You should see your workspace in yourNx Cloud organization.
If you do not see your workspace in Nx Cloud then please follow the steps outlined in theNx Cloud setup.
This is important for using remote caching and self-healing in CI later in the tutorial.
Explore the Nx Workspace Setup
Section titled “Explore the Nx Workspace Setup”Let's take a look at the structure of our new Nx workspace:
Directoryacme
Directoryapps
- demo
Directorypackages
- ui
- eslint.config.mjs
- nx.json
- package-lock.json
- package.json
- tsconfig.base.json
- vitest.workspace.ts
Here are some files that might jump to your eyes:
- The
.nx
folder is where Nx stores local metadata about your workspaces using theNx Daemon. - The
nx.json
file contains configuration settings for Nx itself and global default settings that individual projects inherit. - The
.github/workflows/ci.yml
file preconfigures your CI in GitHub Actions to run build and test through Nx.
Now, let's build some features and see how Nx helps get us to production faster.
Serving the App
Section titled “Serving the App”To serve your new Angular app, run:
npxnxservedemo
The app is served athttp://localhost:4200.
Nx uses the following syntax to run tasks:
Project Configuration
Section titled “Project Configuration”The project tasks are defined in theproject.json
file.
{"name":"demo",..."targets": {"build": {... },"serve": {... },"extract-i18n": {... },"lint": {... },"test": {... },"serve-static": {... },},}
Each target contains a configuration object that tells Nx how to run that target.
{"name":"angular-store",..."targets": {"serve": {"executor":"@angular/build:dev-server","defaultConfiguration":"development","options": {"buildTarget":"angular-store:build"},"configurations": {"development": {"buildTarget":"angular-store:build:development","hmr":true},"production": {"buildTarget":"angular-store:build:production","hmr":false}}},...},}
The most critical parts are:
executor
- this is of the syntax<plugin>:<executor-name>
, where theplugin
is an NPM package containing anNx Plugin and<executor-name>
points to a function that runs the task.options
- these are additional properties and flags passed to the executor function to customize it
To view all tasks for a project, look in theNx Console project detail view or run:
npxnxshowprojectdemo
Modularization with Local Libraries
Section titled “Modularization with Local Libraries”When you develop your Angular application, usually all your logic sits in the app'ssrc
folder. Ideally separated by various folder names which represent your domains or features. As your app grows, however, the app becomes more and more monolithic, which makes building and testing it harder and slower.
Directoryacme/
Directoryapps/
Directorydemo/
Directorysrc/
Directoryapp/
- …
Directorycart/
- …
Directoryproducts/
- …
Directoryorders/
- …
Directoryui/
- …
Nx allows you to separate this logic into "local libraries." The main benefits include
- better separation of concerns
- better reusability
- more explicit private and public boundaries (APIs) between domains and features
- better scalability in CI by enabling independent test/lint/build commands for each library
- better scalability in your teams by allowing different teams to work on separate libraries
Create Local Libraries
Section titled “Create Local Libraries”Let's create a reusable design system library calledui
that we can use across our workspace. This library will contain reusable components such as buttons, inputs, and other UI elements.
npxnxg@nx/angular:librarypackages/ui--unitTestRunner=vitest
Note how we type out the full path in the command to place the library into a subfolder. You can choose whatever folder structure you like to organize your projects.
Running the above command should lead to the following directory structure:
Directoryacme/
Directoryapps/
Directorydemo/
- …
Directorypackages/
- ui
- eslint.config.mjs
- nx.json
- package-lock.json
- package.json
- tsconfig.base.json
- vitest.workspace.ts
Just as with thedemo
app, Nx automatically infers the tasks for theui
library from its configuration files. You can view them by running:
npxnxshowprojectui
In this case, we have thelint
andtest
tasks available, among other inferred tasks.
npxnxlintuinpxnxtestui
Import Libraries into the Demo App
Section titled “Import Libraries into the Demo App”All libraries that we generate are automatically included in the TypeScript path mappings configured in the root-leveltsconfig.base.json
.
{"compilerOptions": {..."paths": {"@acme/ui": ["packages/ui/src/index.ts"]},...},}
Hence, we can easily import them into other libraries and our Angular application.
You can see that theUi
component is exported via theindex.ts
file of ourui
library so that other projects in the repository can use it. This is our public API with the rest of the workspace and is enforced by the library's build configuration. Only export what's necessary to be usable outside the library itself.
export*from'./lib/ui/ui';
Let's add a simpleHero
component that we can use in our demo app.
import { Component, Input, Output, EventEmitter }from'@angular/core';import { CommonModule }from'@angular/common';@Component({selector:'lib-hero',standalone:true,imports: [CommonModule],template:`<div [ngStyle]="containerStyle"><h1 [ngStyle]="titleStyle">{{ title }}</h1><p [ngStyle]="subtitleStyle">{{ subtitle }}</p><button (click)="handleCtaClick()" [ngStyle]="buttonStyle">{{ cta }}</button></div>`,})exportclassHero {@Input() title!:string;@Input() subtitle!:string;@Input() cta!:string;@Output() ctaClick=newEventEmitter<void>();containerStyle= {backgroundColor:'#1a1a2e',color:'white',padding:'100px 20px',textAlign:'center',};titleStyle= {fontSize:'48px',marginBottom:'16px',};subtitleStyle= {fontSize:'20px',marginBottom:'32px',};buttonStyle= {backgroundColor:'#0066ff',color:'white',border:'none',padding:'12px 24px',fontSize:'18px',borderRadius:'4px',cursor:'pointer',};handleCtaClick() {this.ctaClick.emit();}}
Then, export it fromindex.ts
.
export*from'./lib/hero/hero';export*from'./lib/ui/ui';
We're ready to import it into our main application now.
import { Component }from'@angular/core';import { RouterOutlet }from'@angular/router';// importing the component from the libraryimport { Hero }from'@acme/ui';@Component({selector:'app-root',standalone:true,imports: [RouterOutlet, Hero],template:`<lib-herotitle="Welcmoe demo"subtitle="Build something amazing today"cta="Get Started"></lib-hero>`,})exportclassApp {}
Serve your app again (npx nx serve demo
) and you should see the new Hero component from theui
library rendered on the home page.
If you have keen eyes, you may have noticed that there is a typo in theApp
component. This mistake is intentional, and we'll see later how Nx can fix this issue automatically in CI.
Visualize your Project Structure
Section titled “Visualize your Project Structure”Nx automatically detects the dependencies between the various parts of your workspace and builds aproject graph. This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks likenpx nx build
, identifyingaffected projects and more. Interestingly, you can also visualize it.
Just run:
npxnxgraph
You should be able to see something similar to the following in your browser.
Let's create a git branch with the new hero component so we can open a pull request later:
gitcheckout-badd-hero-componentgitadd.gitcommit-m'add hero component'
Testing and Linting - Running Multiple Tasks
Section titled “Testing and Linting - Running Multiple Tasks”Our current setup not only has targets for serving and building the Angular application, but also has targets for unit testing, e2e testing and linting. Thetest
andlint
targets are defined in the applicationproject.json
file. We can use the same syntax as before to run these tasks:
npxnxtestdemo# runs the tests for demonpxnxlintui# runs the linter on ui
More conveniently, we can also run tasks in parallel using the following syntax:
npxnxrun-many-ttestlint
This is exactly what is configured in.github/workflows/ci.yml
for the CI pipeline. Therun-many
command allows you to run multiple tasks across multiple projects in parallel, which is particularly useful in a monorepo setup.
There is a test failure for thedemo
app due to the updated content. Don't worry about it for now, we'll fix it in a moment with the help of Nx Cloud's self-healing feature.
Local Task Cache
Section titled “Local Task Cache”One thing to highlight is that Nx is able tocache the tasks you run.
Note that all of these targets are automatically cached by Nx. If you re-run a single one or all of them again, you'll see that the task completes immediately. In addition, (as can be seen in the output example below) there will be a note that a matching cache result was found and therefore the task was not run again.
✔ nx run ui:lint✔ nx run ui:test✔ nx run demo:lint✖ nx run demo:test—————————————————————————————————————————————————————————————————————————————————————————————————————————NX Ran targets test, lint for 2 projects (1s)✔ 3/4 succeeded [3 read from cache]✖ 1/4 targets failed, including the following:- nx run demo:test
Again, thedemo:test
task failed, but notice that the remaining three tasks were read from cache.
Not all tasks might be cacheable though. You can configure thecache
settings in thetargetDefaults
property of thenx.json
file. You can alsolearn more about how caching works.
Self-Healing CI with Nx Cloud
Section titled “Self-Healing CI with Nx Cloud”In this section, we'll explore how Nx Cloud can help your pull request get to green faster with self-healing CI. Recall that our demo app has a test failure, so let's see how this can be automatically resolved.
Thenpx nx-cloud fix-ci
command that is already included in your GitHub Actions workflow (github/workflows/ci.yml
) is responsible for enabling self-healing CI and will automatically suggest fixes to your failing tasks.
name:CIon:push:branches:-mainpull_request:permissions:actions:readcontents:readjobs:main:runs-on:ubuntu-lateststeps:-uses:actions/checkout@v4with:filter:tree:0fetch-depth:0-uses:actions/setup-node@v4with:node-version:20cache:'npm'-run:npm ci --legacy-peer-deps-run:npx nx run-many -t lint test build-run:npx nx-cloud fix-ciif:always()
You will also need to install theNx Console editor extension for VS Code, Cursor, or IntelliJ. For the complete AI setup guide, see ourAI integration documentation.
Install Nx Console for VSCodeThe official VSCode extension for Nx.
Install Nx Console for JetBrainsAvailable for WebStorm, IntelliJ IDEA Ultimate and more!
Now, let's push theadd-hero-component
branch to GitHub and open a new pull request.
gitpushoriginadd-hero-component# Don't forget to open a pull request on GitHub
As expected, the CI check fails because of the test failure in thedemo
app. But rather than looking at the pull request, Nx Console notifies you that the run has completed, and that it has a suggested fix for the failing test. This means that you don't have to waste timebabysitting your PRs, and the fix can be applied directly from your editor.
Fix CI from Your Editor
Section titled “Fix CI from Your Editor”From the Nx Console notification, you can clickShow Suggested Fix
button. Review the suggested fix, which in this case is to change the typoWelcmoe
to the correctWelcome
spelling. Approve this fix by clickingApplyFix
and that's it!
You didn't have to leave your editor or do any manual work to fix it. This is the power of self-healing CI with Nx Cloud.
Remote Cache for Faster Time To Green
Section titled “Remote Cache for Faster Time To Green”After the fix has been applied and committed, CI will re-run automatically, and you will be notified of the results in your editor.
When you clickView Results
to show the run in Nx Cloud, you'll notice something interesting. The lint and test tasks for theui
library were read from remote cache and did not have to run again, thus each taking less than a second to complete.
This happens because Nx Cloud caches the results of tasks and reuses them across different CI runs. As long as the inputs for each task have not changed (e.g. source code), then their results can be replayed from Nx Cloud'sRemote Cache. In this case, since the last fix was applied only to thedemo
app's source code, none of the tasks forui
library had to be run again.
This significantly speeds up the time to green for your pull requests, because subsequent changes to them have a good chance to replay tasks from cache.
This pull request is now ready to be merged with the help of Nx Cloud's self-healing CI and remote caching.
Next Steps
Section titled “Next Steps”Here are some things you can dive into next:
- Read more abouthow Nx compares to the Angular CLI
- Learn more about theunderlying mental model of Nx
- Learn about popular generators such ashow to setup Tailwind
- Learn how tomigrate your existing Angular CLI repo to Nx
- Learn aboutenforcing boundaries between projects
- Setup Storybook for our shared UI library
Also, make sure you
- ⭐️Star us on GitHub to show your support and stay updated on new releases!
- Join the Official Nx Discord Server to ask questions and find out the latest news about Nx.
- Follow Nx on Twitter to stay up to date with Nx news
- Read our Nx blog
- Subscribe to our Youtube channel for demos and Nx insights