Monorepo Setup (Nx) for Web Project
Nx—not just build system with caching, but full monorepo platform: code generators, plugins for each framework, dependency graph visualization, run only affected projects. Suitable for large teams and complex projects where Turborepo feels insufficient.
Nx vs Turborepo: Principal Difference
Turborepo—task runner with cache. Doesn't understand package contents.
Nx—understands structure: knows this is Next.js app, that one is NestJS, can generate components, modules, tests by templates. Plugin @nx/next configures caching rules, generators, tasks—all automatic.
Turbo fits when stack exists and need speed. Nx fits when team large and need development standardization.
Initialization
# New workspace
npx create-nx-workspace@latest acme --preset=apps
cd acme
# Add applications
npx nx generate @nx/next:app web --directory=apps/web
npx nx generate @nx/react:app admin --directory=apps/admin --bundler=vite
npx nx generate @nx/node:app api --directory=apps/api --framework=express
# Add libraries
npx nx generate @nx/react:lib ui --directory=packages/ui --component
npx nx generate @nx/js:lib utils --directory=packages/utils
npx nx generate @nx/js:lib types --directory=packages/types --bundler=none
Structure and nx.json
// nx.json
{
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"targetDefaults": {
"build": {
"cache": true,
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
},
"lint": {
"cache": true,
"inputs": [
"default",
"{workspaceRoot}/.eslintrc.json",
"{workspaceRoot}/.eslintignore"
]
},
"test": {
"cache": true,
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"]
},
"typecheck": {
"cache": true
}
},
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": [
"default",
"!{projectRoot}/**/*.spec.*",
"!{projectRoot}/jest.config.*",
"!{projectRoot}/.eslintrc.json"
],
"sharedGlobals": []
},
"generators": {
"@nx/react": {
"component": {
"style": "none",
"classComponent": false
}
}
},
"defaultBase": "main"
}
project.json for Each Project
Nx uses project.json instead of scripts in package.json:
// apps/web/project.json
{
"name": "web",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/web/src",
"projectType": "application",
"targets": {
"build": {
"executor": "@nx/next:build",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production"
},
"serve": {
"executor": "@nx/next:server",
"defaultConfiguration": "development"
}
},
"tags": ["type:app", "scope:web"]
}
Tags and Lint Rules for Architectural Constraints
Nx strength—enforce module boundaries:
// .eslintrc.json
{
"plugins": ["@nx"],
"rules": {
"@nx/enforce-module-boundaries": [
"error",
{
"depConstraints": [
{
"sourceTag": "type:app",
"onlyDependOnLibsWithTags": ["type:lib"]
},
{
"sourceTag": "scope:web",
"onlyDependOnLibsWithTags": ["scope:web", "scope:shared"]
}
]
}
]
}
}
Dependency Graph
# Browser visualization
npx nx graph
# Affected by branch changes
npx nx affected:graph
Run Only Affected Projects
# Tests for affected only
npx nx affected:test
# Build changed
npx nx affected:build --base=origin/main --head=HEAD
# Parallel, max 4 tasks
npx nx affected:build --parallel=4
Generators: Standardize Development
Nx lets write custom generators—scripts creating files by templates.
Nx Cloud: Distributed Task Execution
Distribute tasks across multiple CI agents:
# .github/workflows/ci.yml
jobs:
agents:
strategy:
matrix:
agent: [1, 2, 3]
steps:
- run: npx nx-cloud start-agent
main:
steps:
- run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js"
- run: npx nx affected -t lint typecheck test build
Timeline
Setup Nx for 6–10 projects—3–5 days: workspace, plugins, module boundaries, generators, CI/CD. Migrate existing monorepo—1–1.5 weeks depending on custom configs.







