Building React Apps in an Nx Monorepo
In this tutorial you'll learn how to use React with Nx in a monorepo (integrated) setup.
What are you going to learn?
- how to create a new React application
- how to run a single task (i.e. serve your app) or run multiple tasks in parallel
- how to leverage code generators to scaffold components
- how to modularize your codebase and impose architectural constraints for better maintainability
Note, this tutorial sets up a repo with applications and libraries in their own subfolders. If you are looking for a React standalone app setup then check out our React standalone app tutorial.
Why Use an Integrated Monorepo?
An integrated monorepo is a repository configured with a set of features that work together toward the goal of allowing developers to focus on building features rather than the configuration, coordination and maintenance of the tooling in the repo.
You'll notice that instead of using npm/yarn/pnpm workspaces, projects within the repository are linked using typescript path aliases that are defined in the tsconfig.base.json
file. Also, since we're creating projects using Nx plugin generators, all new projects come preconfigured with useful tools like Prettier, ESLint and Jest.
Nx Plugins are optional packages that extend the capabilities of Nx, catering to various specific technologies. For instance, we have plugins tailored to React (e.g., @nx/react
), Vite (@nx/vite
), Cypress (@nx/cypress
), and more. These plugins offer additional features, making your development experience more efficient and enjoyable when working with specific tech stacks.
Features of an integrated monorepo:
- Install dependencies at the root by default
- Scaffold new code with generators
- Updates dependencies with automated migrations
Visit our "Why Nx" page for more details.
Final Code
Here's the source code of the final result for this tutorial.
Example repository/nrwl/nx-recipes/tree/main/react-monorepo
Creating a new React Monorepo
Create a new React monorepo with the following command:
~❯
npx create-nx-workspace@latest react-monorepo --preset=react-monorepo
1
2NX Let's create a new workspace [https://nx.dev/getting-started/intro]
3
4✔ Application name · react-store
5✔ Which bundler would you like to use? · vite
6✔ Test runner to use for end to end (E2E) tests · cypress
7✔ Default stylesheet format · css
8✔ Do you want Nx Cloud to make your CI fast? · Yes
9
Let's name the initial application react-store
. In this tutorial we're going to use vite
as a bundler, cypress
for e2e tests and css
for styling. The above command generates the following structure:
1└─ react-monorepo
2 ├─ ...
3 ├─ apps
4 │ ├─ react-store
5 │ │ ├─ public
6 │ │ │ └─ ...
7 │ │ ├─ src
8 │ │ │ ├─ app
9 │ │ │ │ ├─ app.module.css
10 │ │ │ │ ├─ app.spec.tsx
11 │ │ │ │ ├─ app.tsx
12 │ │ │ │ └─ nx-welcome.tsx
13 │ │ │ ├─ assets
14 │ │ │ ├─ main.tsx
15 │ │ │ └─ styles.css
16 │ │ ├─ index.html
17 │ │ ├─ project.json
18 │ │ ├─ tsconfig.app.json
19 │ │ ├─ tsconfig.json
20 │ │ ├─ tsconfig.spec.json
21 │ │ └─ vite.config.ts
22 │ └─ react-store-e2e
23 │ └─ ...
24 ├─ nx.json
25 ├─ tsconfig.base.json
26 └─ package.json
27
The setup includes..
- a new React application (
apps/react-store/
) - a Cypress based set of e2e tests (
apps/react-store-e2e/
) - Prettier preconfigured
- ESLint preconfigured
- Jest preconfigured
Typically, an integrated Nx workspace places application projects in the apps
folder and library projects in the libs
folder. Applications are encouraged to be as light-weight as possible so that more code is pushed into libraries and can be reused in other projects. This folder structure is just a suggestion and can be modified to suit your organization's needs.
The nx.json
file contains configuration settings for Nx itself and global default settings that individual projects inherit. The apps/react-store/project.json
file contains settings that are specific to the react-store
project. We'll examine that file more in the next section.
Serving the App
To serve your new React application, just run:
❯
nx serve react-store
Your application should be served at http://localhost:4200.
Nx uses the following syntax to run tasks:
Inferred Tasks
Nx identifies available tasks for your project from tooling configuration files, package.json
scripts and the targets defined in project.json
. To view the tasks that Nx has detected, look in the Nx Console project detail view or run:
❯
nx show project react-store --web
react-store
Root: apps/react-store
Type: Application
Targets
build
vite build
Cacheable
If you expand the build
task, you can see that it was created by the @nx/vite
plugin by analyzing your vite.config.ts
file. Notice the outputs are defined as {workspaceRoot}/dist/apps/react-store
. This value is being read from the build.outDir
defined in your vite.config.ts
file. Let's change that value in your vite.config.ts
file:
1export default defineConfig({
2 // ...
3 build: {
4 outDir: './build/react-store',
5 // ...
6 },
7});
8
Now if you look at the project details view, the outputs for the build target will say {workspaceRoot}/build/react-store
. This feature ensures that Nx will always cache the correct files.
You can also override the settings for inferred tasks by modifying the targetDefaults
in nx.json
or setting a value in your project.json
file. Nx will merge the values from the inferred tasks with the values you define in targetDefaults
and in your specific project's configuration.
Adding Another Application
Nx plugins usually provide generators that allow you to easily scaffold code, configuration or entire projects. To see what capabilities the @nx/react
plugin provides, run the following command and inspect the output:
react-monorepo❯
npx nx list @nx/react
1
2NX Capabilities in @nx/react:
3
4 GENERATORS
5
6 init : Initialize the `@nrwl/react` plugin.
7 application : Create a React application.
8 library : Create a React library.
9 component : Create a React component.
10 redux : Create a Redux slice for a project.
11 storybook-configuration : Set up storybook for a React app or library.
12 component-story : Generate storybook story for a React component
13 stories : Create stories/specs for all components declared in an app or library.
14 component-cypress-spec : Create a Cypress spec for a UI component that has a story.
15 hook : Create a hook.
16 cypress-component-configuration : Setup Cypress component testing for a React project
17 component-test : Generate a Cypress component test for a React component
18 setup-tailwind : Set up Tailwind configuration for a project.
19 setup-ssr : Set up SSR configuration for a project.
20 host : Generate a host react application
21 remote : Generate a remote react application
22 federate-module : Federate a module.
23
24 EXECUTORS/BUILDERS
25
26 module-federation-dev-server : Serve a host or remote application.
27 module-federation-ssr-dev-server : Serve a host application along with it's known remotes.
28
If you prefer a more integrated experience, you can install the "Nx Console" extension for your code editor. It has support for VSCode, IntelliJ and ships a LSP for Vim. Nx Console provides autocompletion support in Nx configuration files and has UIs for browsing and running generators.
More info can be found in the integrate with editors article.
Run the following command to generate a new inventory
application. Note how we append --dry-run
to first check the output.
react-monorepo❯
npx nx g @nx/react:app inventory --directory=apps/inventory --dry-run
1NX Generating @nx/react:application
2
3✔ Would you like to add React Router to this application? (y/N) · false
4✔ Which E2E test runner would you like to use? · cypress
5✔ What should be the project name and where should it be generated? · inventory @ apps/inventory
6CREATE apps/inventory/index.html
7CREATE apps/inventory/public/favicon.ico
8CREATE apps/inventory/src/app/app.spec.tsx
9CREATE apps/inventory/src/assets/.gitkeep
10CREATE apps/inventory/src/main.tsx
11CREATE apps/inventory/tsconfig.app.json
12CREATE apps/inventory/src/app/nx-welcome.tsx
13CREATE apps/inventory/src/app/app.module.css
14CREATE apps/inventory/src/app/app.tsx
15CREATE apps/inventory/src/styles.css
16CREATE apps/inventory/tsconfig.json
17CREATE apps/inventory/project.json
18CREATE apps/inventory/tsconfig.spec.json
19CREATE apps/inventory/vite.config.ts
20CREATE apps/inventory/.eslintrc.json
21CREATE apps/inventory-e2e/project.json
22CREATE apps/inventory-e2e/src/e2e/app.cy.ts
23CREATE apps/inventory-e2e/src/support/app.po.ts
24CREATE apps/inventory-e2e/src/support/e2e.ts
25CREATE apps/inventory-e2e/src/fixtures/example.json
26CREATE apps/inventory-e2e/src/support/commands.ts
27CREATE apps/inventory-e2e/cypress.config.ts
28CREATE apps/inventory-e2e/tsconfig.json
29CREATE apps/inventory-e2e/.eslintrc.json
30
31NOTE: The "dryRun" flag means no changes were made.
32
As you can see, it generates a new application in the apps/inventory/
folder. Let's actually run the generator by removing the --dry-run
flag.
❯
npx nx g @nx/react:app inventory --directory=apps/inventory
Sharing Code with Local Libraries
When you develop your React application, usually all your logic sits in the app
folder. Ideally separated by various folder names which represent your "domains". As your app grows, however, the app becomes more and more monolithic and the code is unable to be shared with other applications.
1└─ react-monorepo
2 ├─ ...
3 ├─ apps
4 │ └─ react-store
5 │ ├─ ...
6 │ ├─ src
7 │ │ ├─ app
8 │ │ │ ├─ products
9 │ │ │ ├─ cart
10 │ │ │ ├─ ui
11 │ │ │ ├─ ...
12 │ │ │ └─ app.tsx
13 │ │ ├─ ...
14 │ │ └─ main.tsx
15 │ ├─ ...
16 │ └─ project.json
17 ├─ nx.json
18 ├─ ...
19
Nx allows you to separate this logic into "local libraries". The main benefits include
- better separation of concerns
- better reusability
- more explicit "APIs" between your "domain areas"
- 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
Creating Local Libraries
Let's assume our domain areas include products
, orders
and some more generic design system components, called ui
. We can generate a new library for each of these areas using the React library generator:
1nx g @nx/react:library products --directory=libs/products --unitTestRunner=vitest --bundler=none
2nx g @nx/react:library orders --directory=libs/orders --unitTestRunner=vitest --bundler=none
3nx g @nx/react:library shared-ui --directory=libs/shared/ui --unitTestRunner=vitest --bundler=none
4
Note how we type out the full path in the directory
flag to place the libraries into a subfolder. You can choose whatever folder structure you like to organize your projects. If you change your mind later, you can run the move generator to move a project to a different folder.
Running the above commands should lead to the following directory structure:
1└─ react-monorepo
2 ├─ ...
3 ├─ apps
4 ├─ libs
5 │ ├─ products
6 │ │ ├─ ...
7 │ │ ├─ project.json
8 │ │ ├─ src
9 │ │ │ ├─ index.ts
10 │ │ │ └─ lib
11 │ │ │ ├─ products.spec.ts
12 │ │ │ └─ products.ts
13 │ │ ├─ tsconfig.json
14 │ │ ├─ tsconfig.lib.json
15 │ │ ├─ tsconfig.spec.json
16 │ │ └─ vite.config.ts
17 │ ├─ orders
18 │ │ ├─ ...
19 │ │ ├─ project.json
20 │ │ ├─ src
21 │ │ │ ├─ index.ts
22 │ │ │ └─ ...
23 │ │ └─ ...
24 │ └─ shared
25 │ └─ ui
26 │ ├─ ...
27 │ ├─ project.json
28 │ ├─ src
29 │ │ ├─ index.ts
30 │ │ └─ ...
31 │ └─ ...
32 ├─ ...
33
Each of these libraries
- has a project details view where you can see the available tasks (e.g. running tests for just orders:
nx test orders
) - has its own
project.json
file where you can customize targets - has the name you specified in the generate command; you can find the name in the corresponding
project.json
file - has a dedicated
index.ts
file which is the "public API" of the library - is mapped in the
tsconfig.base.json
at the root of the workspace
Importing Libraries into the React Applications
All libraries that we generate automatically have aliases created in the root-level tsconfig.base.json
.
1{
2 "compilerOptions": {
3 ...
4 "paths": {
5 "@react-monorepo/products": ["libs/products/src/index.ts"],
6 "@react-monorepo/orders": ["libs/orders/src/index.ts"],
7 "@react-monorepo/shared-ui": ["libs/shared/ui/src/index.ts"]
8 },
9 ...
10 },
11}
12
Hence we can easily import them into other libraries and our React application. As an example, let's create and expose a ProductList
component from our libs/products
library. Either create it by hand or run
❯
nx g @nx/react:component product-list --project=products --directory="libs/products/src/lib/product-list"
We don't need to implement anything fancy as we just want to learn how to import it into our main React application.
1import styles from './product-list.module.css';
2
3/* eslint-disable-next-line */
4export interface ProductListProps {}
5
6export function ProductList(props: ProductListProps) {
7 return (
8 <div className={styles['container']}>
9 <h1>Welcome to ProductList!</h1>
10 </div>
11 );
12}
13
14export default ProductList;
15
Make sure the ProductList
is exported via the index.ts
file of our products
library. This is our public API with the rest of the workspace. Only export what's really necessary to be usable outside the library itself.
1export * from './lib/product-list/product-list';
2
We're ready to import it into our main application now. First (if you haven't already), let's set up React Router.
❯
npm add react-router-dom
Configure it in the main.tsx
.
1import { StrictMode } from 'react';
2import { BrowserRouter } from 'react-router-dom';
3import ReactDOM from 'react-dom/client';
4
5import App from './app/app';
6
7const root = ReactDOM.createRoot(
8 document.getElementById('root') as HTMLElement
9);
10
11root.render(
12 <StrictMode>
13 <BrowserRouter>
14 <App />
15 </BrowserRouter>
16 </StrictMode>
17);
18
Then we can import the ProductList
component into our app.tsx
and render it via the routing mechanism whenever a user hits the /products
route.
1import { Route, Routes } from 'react-router-dom';
2
3// importing the component from the library
4import { ProductList } from '@react-monorepo/products';
5
6function Home() {
7 return <h1>Home</h1>;
8}
9
10export function App() {
11 return (
12 <Routes>
13 <Route path="/" element={<Home />}></Route>
14 <Route path="/products" element={<ProductList />}></Route>
15 </Routes>
16 );
17}
18
19export default App;
20
Serving your app (nx serve react-store
) and then navigating to /products
should give you the following result:
Let's apply the same for our orders
library.
- generate a new component
OrderList
inlibs/orders
and export it in the correspondingindex.ts
file - import it into the
app.tsx
and render it via the routing mechanism whenever a user hits the/orders
route
In the end, your app.tsx
should look similar to this:
1import { Route, Routes } from 'react-router-dom';
2import { ProductList } from '@react-monorepo/products';
3import { OrderList } from '@react-monorepo/orders';
4
5function Home() {
6 return <h1>Home</h1>;
7}
8
9export function App() {
10 return (
11 <Routes>
12 <Route path="/" element={<Home />}></Route>
13 <Route path="/products" element={<ProductList />}></Route>
14 <Route path="/orders" element={<OrderList />}></Route>
15 </Routes>
16 );
17}
18
19export default App;
20
Let's also show products in the inventory
app.
1import { ProductList } from '@react-monorepo/products';
2
3export function App() {
4 return <ProductList />;
5}
6
7export default App;
8
Visualizing your Project Structure
Nx automatically detects the dependencies between the various parts of your workspace and builds a project graph. This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like nx build
, identifying affected projects and more. Interestingly you can also visualize it.
Just run:
❯
nx graph
You should be able to see something similar to the following in your browser.
Notice how shared-ui
is not yet connected to anything because we didn't import it in any of our projects.
Exercise for you: change the codebase such that shared-ui
is used by orders
and products
. Note: you need to restart the nx graph
command to update the graph visualization or run the CLI command with the --watch
flag.
Testing and Linting - Running Multiple Tasks
Our current setup doesn't just come with targets for serving and building the React application, but also has targets for unit testing, e2e testing and linting. Again, these are defined in the project.json
file. We can use the same syntax as before to run these tasks:
1nx test react-store # runs the tests for react-store
2nx lint inventory # runs the linter on inventory
3nx e2e react-store-e2e # runs e2e tests for the react-store
4
More conveniently, we can also run tasks in parallel using the following syntax:
❯
nx run-many -t test
Caching
One thing to highlight is that Nx is able to cache 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.
react-monorepo❯
nx run-many -t test lint e2e
1✔ nx run e2e:lint [existing outputs match the cache, left as is]
2✔ nx run react-store:lint [existing outputs match the cache, left as is]
3✔ nx run react-store:test [existing outputs match the cache, left as is]
4✔ nx run e2e:e2e [existing outputs match the cache, left as is]
5
6——————————————————————————————————————————————————————
7
8NX Successfully ran targets test, lint, e2e for 5 projects (54ms)
9
10Nx read the output from the cache instead of running the command for 10 out of 10 tasks.
11
Not all tasks might be cacheable though. You can configure the cache
settings in the targetDefaults
property of the nx.json
file. You can also learn more about how caching works.
Testing Affected Projects
Commit your changes to git.
❯
git commit -a -m "some commit message"
And then make a small change to the products
library.
1import styles from './product-list.module.css';
2
3/* eslint-disable-next-line */
4export interface ProductListProps {}
5
6export function ProductList(props: ProductListProps) {
7 return (
8 <div className={styles['container']}>
9 <h1>Welcome to ProductList!</h1>
10 <p>This is a change. 👋</p>
11 </div>
12 );
13}
14
15export default ProductList;
16
One of the key features of Nx in a monorepo setting is that you're able to run tasks only for projects that are actually affected by the code changes that you've made. To run the tests for only the projects affected by this change, run:
❯
nx affected -t test
Note that the unit tests were run for products
, react-store
and inventory
, but not for orders
because a change to products
can not possibly break the tests for orders
. In a small repo like this, there isn't a lot of time saved, but as there are more tests and more projects, this quickly becomes an essential command.
You can also see what projects are affected in the graph visualizer with;
❯
nx graph --affected
Building the Apps for Deployment
If you're ready and want to ship your applications, you can build them using
react-monorepo❯
npx nx run-many -t build
1vite v4.3.5 building for production...
2✓ 33 libs transformed.
3dist/react-store/index.html 0.48 kB │ gzip: 0.30 kB
4dist/react-store/assets/index-e3b0c442.css 0.00 kB │ gzip: 0.02 kB
5dist/react-store/assets/index-378e8124.js 165.64 kB │ gzip: 51.63 kB
6✓ built in 496ms
7
8——————————————————————————————————————————————————————————————————————————————————————————————————————————
9
10NX Successfully ran target build for project reactutorial (1s)
11
All the required files will be placed in dist/react-store
and dist/inventory
and can be deployed to your favorite hosting provider.
You can even create your own deploy
task that sends the build output to your hosting provider.
1{
2 "targets": {
3 "deploy": {
4 "dependsOn": ["build"],
5 "command": "netlify deploy --dir=dist/react-store"
6 }
7 }
8}
9
Replace the command
with whatever terminal command you use to deploy your site.
The "dependsOn": ["build"]
setting tells Nx to make sure that the project's build
task has been run successfully before the deploy
task.
With the deploy
tasks defined, you can deploy a single application with nx deploy react-store
or deploy any applications affected by the current changes with:
❯
nx affected -t deploy
Imposing Constraints with Module Boundary Rules
Once you modularize your codebase you want to make sure that the libs are not coupled to each other in an uncontrolled way. Here are some examples of how we might want to guard our small demo workspace:
- we might want to allow
orders
to import fromshared-ui
but not the other way around - we might want to allow
orders
to import fromproducts
but not the other way around - we might want to allow all libraries to import the
shared-ui
components, but not the other way around
When building these kinds of constraints you usually have two dimensions:
- type of project: what is the type of your library. Example: "feature" library, "utility" library, "data-access" library, "ui" library
- scope (domain) of the project: what domain area is covered by the project. Example: "orders", "products", "shared" ... this really depends on the type of product you're developing
Nx comes with a generic mechanism that allows you to assign "tags" to projects. "tags" are arbitrary strings you can assign to a project that can be used later when defining boundaries between projects. For example, go to the project.json
of your orders
library and assign the tags type:feature
and scope:orders
to it.
1{
2 ...
3 "tags": ["type:feature", "scope:orders"]
4}
5
Then go to the project.json
of your products
library and assign the tags type:feature
and scope:products
to it.
1{
2 ...
3 "tags": ["type:feature", "scope:products"]
4}
5
Finally, go to the project.json
of the shared-ui
library and assign the tags type:ui
and scope:shared
to it.
1{
2 ...
3 "tags": ["type:ui", "scope:shared"]
4}
5
Notice how we assign scope:shared
to our UI library because it is intended to be used throughout the workspace.
Next, let's come up with a set of rules based on these tags:
type:feature
should be able to import fromtype:feature
andtype:ui
type:ui
should only be able to import fromtype:ui
scope:orders
should be able to import fromscope:orders
,scope:shared
andscope:products
scope:products
should be able to import fromscope:products
andscope:shared
To enforce the rules, Nx ships with a custom ESLint rule. Open the .eslintrc.base.json
at the root of the workspace and add the following depConstraints
in the @nx/enforce-module-boundaries
rule configuration:
1{
2 ...
3 "overrides": [
4 {
5 ...
6 "rules": {
7 "@nx/enforce-module-boundaries": [
8 "error",
9 {
10 "enforceBuildableLibDependency": true,
11 "allow": [],
12 "depConstraints": [
13 {
14 "sourceTag": "*",
15 "onlyDependOnLibsWithTags": ["*"]
16 },
17 {
18 "sourceTag": "type:feature",
19 "onlyDependOnLibsWithTags": ["type:feature", "type:ui"]
20 },
21 {
22 "sourceTag": "type:ui",
23 "onlyDependOnLibsWithTags": ["type:ui"]
24 },
25 {
26 "sourceTag": "scope:orders",
27 "onlyDependOnLibsWithTags": [
28 "scope:orders",
29 "scope:products",
30 "scope:shared"
31 ]
32 },
33 {
34 "sourceTag": "scope:products",
35 "onlyDependOnLibsWithTags": ["scope:products", "scope:shared"]
36 },
37 {
38 "sourceTag": "scope:shared",
39 "onlyDependOnLibsWithTags": ["scope:shared"]
40 }
41 ]
42 }
43 ]
44 }
45 },
46 ...
47 ]
48}
49
To test it, go to your libs/products/src/lib/product-list/product-list.tsx
file and import the OrderList
from the orders
project:
1import styles from './product-list.module.css';
2
3// This import is not allowed 👇
4import { OrderList } from '@react-monorepo/orders';
5
6/* eslint-disable-next-line */
7export interface ProductListProps {}
8
9export function ProductList(props: ProductListProps) {
10 return (
11 <div className={styles['container']}>
12 <h1>Welcome to ProductList!</h1>
13 <OrderList />
14 </div>
15 );
16}
17
18export default ProductList;
19
If you lint your workspace you'll get an error now:
❯
nx run-many -t lint
1 Running target lint for 7 projects
2✖ nx run products:lint
3 Linting "products"...
4
5 /Users/isaac/Documents/code/nx-recipes/react-monorepo/libs/products/src/lib/product-list/product-list.tsx
6 4:1 error A project tagged with "scope:products" can only depend on libs tagged with "scope:products", "scope:shared" @nx/enforce-module-boundaries
7 4:10 warning 'OrderList' is defined but never used @typescript-eslint/no-unused-vars
8
9 ✖ 2 problems (1 error, 1 warning)
10
11 Lint warnings found in the listed files.
12
13 Lint errors found in the listed files.
14
15
16✔ nx run orders:lint (996ms)
17✔ nx run react-store:lint (1s)
18✔ nx run react-store-e2e:lint (581ms)
19✔ nx run inventory-e2e:lint (588ms)
20✔ nx run inventory:lint (836ms)
21✔ nx run shared-ui:lint (753ms)
22
23————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
24
25NX Ran target lint for 7 projects (2s)
26
27✔ 6/7 succeeded [0 read from cache]
28
29✖ 1/7 targets failed, including the following:
30 - nx run products:lint
31
If you have the ESLint plugin installed in your IDE you should immediately see an error:
Learn more about how to enforce module boundaries.
Setup CI for Your React Monorepo
This tutorial walked you through how Nx can improve the developer experience for local development, but Nx can also make a big difference in CI. Without adequate tooling, CI times tend to grow exponentially with the size of the codebase. Nx helps reduce wasted time in CI with the affected
command and Nx Replay's remote caching. Nx also efficiently parallelizes tasks across machines with Nx Agents.
To set up Nx Cloud run:
❯
nx connect
And click the link provided. You'll need to follow the instructions on the website to sign up for your account.
Then you can set up your CI with the following command:
❯
nx generate ci-workflow --ci=github
You can choose github
, circleci
, azure
, bitbucket-pipelines
, or gitlab
for the ci
flag.
This will create a default CI configuration that sets up Nx Cloud to use distributed task execution. This automatically runs all tasks on separate machines in parallel wherever possible, without requiring you to manually coordinate copying the output from one machine to another.
Check out one of these detailed tutorials on setting up CI with Nx:
Next Steps
Here's some things you can dive into next:
- Learn more about the underlying mental model of Nx
- Learn how to migrate your React app to Nx
- Learn how to setup Tailwind
- Setup Storybook for our shared UI library
Also, make sure you
- 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