Nx Monorepo Series 1: Introduction & Spring Boot Integration
Part 1 of 5: Building Enterprise-Grade Monorepos with Nx
Learn how to set up a modern monorepo using Nx and integrate Spring Boot applications - the same architecture used by Google, Facebook, and other tech giants.
What is a Monorepo?
A monorepo (monolithic repository) is a software development strategy where code for multiple projects is stored in a single repository. Instead of having separate repositories for each project, application, or library, everything lives together in one unified codebase.
Key Characteristics
- Single Repository: All code lives in one Git repository
- Multiple Projects: Contains multiple applications, services, and libraries
- Shared Dependencies: Common code and dependencies are shared across projects
- Unified Versioning: Single source of truth for versions and configurations
- Atomic Commits: Changes across multiple projects can be committed together
Example Structure
my-company-monorepo/
โโโ apps/
โ โโโ web-app/ # React frontend
โ โโโ mobile-app/ # React Native app
โ โโโ api-service/ # Node.js backend
โ โโโ admin-dashboard/ # Angular admin panel
โโโ libs/
โ โโโ shared-ui/ # Shared UI components
โ โโโ auth/ # Authentication library
โ โโโ data-models/ # Shared data models
โ โโโ utils/ # Utility functions
โโโ tools/
โโโ scripts/ # Build and deployment scripts
What is Nx?
Nx is a powerful open-source build system and monorepo management tool that takes monorepo development to the next level.
Core Features
1. Smart Build System
- Only rebuilds what changed
- Distributed task execution
- Computation caching (local and remote)
2. Dependency Graph
- Understands project relationships
- Visualizes dependencies
- Runs tasks in optimal order
3. Code Generators
- Scaffolds new projects quickly
- Ensures consistency across codebase
- Reduces boilerplate
4. Integrated Tooling
- Built-in support for testing, linting, building
- Plugin ecosystem for popular frameworks
- IDE integration
5. Scalability
- Handles hundreds of projects
- Efficient CI/CD pipelines
- Distributed caching with Nx Cloud
Supported Technologies
- Frontend: React, Angular, Vue, Next.js, React Native
- Backend: Node.js, NestJS, Express
- Mobile: React Native, Expo, Ionic
- Build Tools: Webpack, Vite, esbuild, Rollup
- JVM: Java (Gradle, Maven), Kotlin, Scala
- Other: Python, Go, .NET
Why Use a Monorepo?
1. Code Sharing Made Easy
Before Monorepo (Polyrepo):
- Publish library to npm
- Update package.json in 5 different repos
- Deal with version conflicts
- Wait for CI/CD pipelines
With Monorepo:
- Import directly from shared library
- Changes are immediately available
- Single version, no conflicts
- Refactor across all projects at once
2. Atomic Changes
// Single commit can update:
// - API endpoint in backend
// - API client in shared library
// - UI component using the API
// - Tests for all affected code
// - Documentation
// This is impossible in polyrepo without:
// - Multiple PRs across repos
// - Coordinated merges
// - Version management headaches
3. Consistent Tooling
- One ESLint config for all projects
- One TypeScript config
- One testing framework setup
- One CI/CD pipeline
- One set of dependencies to manage
4. Better Refactoring
- IDE can refactor across all projects
- Find all usages of a function across the entire codebase
- Rename safely with confidence
- No broken dependencies between repos
5. Improved CI/CD Efficiency
# Nx only runs tasks for affected projects
nx affected -t test # Only test changed projects
nx affected -t build # Only build what's needed
nx affected -t lint # Only lint changed code
# See which projects are affected
nx show projects --affected
# Visualize affected project graph
nx graph --affected
# Traditional approach: Run everything, every time
6. Enhanced Developer Experience
- Clone once, work on everything
- Single onboarding process
- Easier to discover and reuse code
- Consistent coding standards
Monorepo vs Polyrepo
Polyrepo (Multiple Repositories)
company-frontend/ (separate repo)
company-backend/ (separate repo)
company-mobile/ (separate repo)
company-shared-lib/ (separate repo, published to npm)
Advantages:
- โ Clear ownership boundaries
- โ Independent deployment
- โ Smaller repository size
- โ Team autonomy
Disadvantages:
- โ Difficult to share code
- โ Version management complexity
- โ Coordinated changes require multiple PRs
- โ Duplicate dependencies
- โ Inconsistent tooling
- โ Hard to refactor across projects
Monorepo (Single Repository)
company-monorepo/
โโโ apps/
โ โโโ frontend/
โ โโโ backend/
โ โโโ mobile/
โโโ libs/
โโโ shared/
Advantages:
- โ Easy code sharing
- โ Atomic changes
- โ Single source of truth
- โ Consistent tooling
- โ Better refactoring
- โ Simplified dependency management
Disadvantages:
- โ Requires proper tooling (Nx solves this)
- โ Larger repository (mitigated by Nx caching)
- โ Need for good monorepo practices
- โ Potential for tight coupling (if not careful)
Real-World Examples
Google - The Largest Monorepo
Statistics:
- 86 TB of data (as of 2015)
- 2 billion lines of code
- 35 million commits
- Thousands of developers
- Millions of files
Tool Used: Google created Bazel (now open-source)
Why Google Uses Monorepo:
- Code reuse across entire company
- Unified tooling and standards
- Large-scale refactoring capabilities
- Atomic changes across services
- Single version of every dependency
- Easier collaboration
Facebook/Meta
- Hundreds of thousands of files
- React, React Native, Jest developed here
- Code sharing between Facebook, Instagram, WhatsApp
- Tool: Custom Mercurial + Buck build system
Microsoft
- Windows operating system
- Office suite
- Many internal tools
- Tool: Git with Virtual File System (VFS for Git)
Other Notable Companies
- Uber: Bazel (thousands of microservices)
- Airbnb: Bazel + Custom tooling
- Twitter: Bazel + Pants
When to Use a Monorepo
โ Ideal Use Cases
-
Multiple Related Applications
- E-commerce platform with web, mobile, admin panel
- SaaS product with customer app + admin dashboard
- Microservices that share code
-
Shared Libraries
- UI component library used across apps
- Common utilities and functions
- Shared data models
-
Full-Stack Development
- Frontend + Backend in same repo
- Type sharing between client and server
- API contracts in one place
-
Platform Products
- Multiple products sharing infrastructure
- White-label applications
- Multi-tenant systems
-
Enterprise Applications
- Large organizations with many teams
- Need for consistency
- Complex dependencies
โ When to Avoid Monorepo
-
Completely Independent Products
- No shared code
- Different teams, different stacks
- No coordination needed
-
Some Open Source Projects
- Contributors may only care about one part
- Separate release cycles
- Different governance models
-
Very Different Tech Stacks
- No overlap in dependencies
- No shared tooling
- No benefit from unified workflow
Nx Architecture
Core Components
1. Nx Workspace Structure
my-workspace/
โโโ nx.json # Nx configuration
โโโ package.json # Dependencies (optional)
โโโ apps/ # Applications
โโโ libs/ # Libraries
โโโ .nx/ # Nx cache and metadata
2. Project Configuration
// apps/my-app/project.json
{
"name": "my-app",
"projectType": "application",
"targets": {
"build": { "executor": "@nx/webpack:webpack" },
"serve": { "executor": "@nx/webpack:dev-server" },
"test": { "executor": "@nx/jest:jest" }
}
}
3. Dependency Graph
Nx provides visual representation of project dependencies:
nx graph # Opens browser with interactive graph
4. Computation Caching
# First run: Actually builds
nx build my-app # Takes 30s
# Second run: From cache
nx build my-app # Takes 0.1s โก
Step-by-Step: Creating Nx Monorepo from Scratch
Prerequisites
Ensure you have the following installed:
# Node.js v18 or higher
node --version
# npm
npm --version
# Java 17+ (for Spring Boot)
java -version
# Git
git --version
Step 1: Create Empty Git Repository
# Create directory
mkdir my-monorepo
cd my-monorepo
# Initialize git
git init
# Create initial README
echo "# My Monorepo" > README.md
git add README.md
git commit -m "Initial commit"
Step 2: Initialize Nx
# Initialize Nx with npm preset
npx nx@latest init --preset=npm --workspaceType=integrated --nxCloud=skip
Command Breakdown:
nx@latest init- Initializes Nx in current directory--preset=npm- Uses npm for package management--workspaceType=integrated- Creates integrated monorepo--nxCloud=skip- Skips Nx Cloud setup (can add later)
Step 3: Verify Installation
# Check created files
ls -la
# You should see:
# - nx.json (Nx configuration)
# - .gitignore (Git ignore file)
# - nx / nx.bat (Nx wrapper scripts)
# - .nx/ (Nx cache and installation)
# Check Nx version
./nx --version
# List available plugins
./nx list
Step 4: Understand Generated Structure
my-monorepo/
โโโ .git/ # Git repository
โโโ .gitignore # Git ignore patterns
โโโ .nx/ # Nx installation and cache
โ โโโ nxw.js # JavaScript wrapper
โ โโโ installation/ # Nx packages
โโโ nx # Unix wrapper script
โโโ nx.bat # Windows wrapper script
โโโ nx.json # Nx configuration
โโโ README.md # Documentation
Step 5: Initial nx.json Configuration
{
"installation": {
"version": "22.2.3"
},
"$schema": "./node_modules/nx/schemas/nx-schema.json"
}
Step 6: Commit Initial Setup
git add .
git commit -m "Initialize Nx monorepo"
Adding Spring Boot to Nx
Now letโs integrate Spring Boot with our Nx workspace.
Step 1: Install Gradle Plugin
# Method A: Using Nx (may be slower)
./nx add @nx/gradle
# Method B: Direct installation (faster)
cd .nx/installation
npm install @nx/gradle@22.2.3
cd ../..
Step 2: Update nx.json
{
"installation": {
"version": "22.2.3",
"plugins": {
"@nx/gradle": "22.2.3"
}
},
"$schema": "./node_modules/nx/schemas/nx-schema.json"
}
Step 3: Initialize Gradle Support
./nx generate @nx/gradle:init
This updates your nx.json with Gradle plugin configuration:
{
"installation": {
"version": "22.2.3",
"plugins": {
"@nx/gradle": "22.2.3"
}
},
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"plugins": [
{
"plugin": "@nx/gradle",
"options": {
"testTargetName": "test",
"classesTargetName": "classes",
"buildTargetName": "build"
}
}
],
"namedInputs": {
"default": ["{projectRoot}/**/*"],
"production": ["default", "!{projectRoot}/src/test/**/*"]
}
}
Step 4: Create Apps Directory
mkdir -p apps
Step 5: Generate Spring Boot Project
Use Spring Initializr to create your project:
curl https://start.spring.io/starter.zip \
-d dependencies=web,data-jpa,h2,actuator \
-d type=gradle-project \
-d language=java \
-d bootVersion=3.4.0 \
-d javaVersion=21 \
-d groupId=com.example \
-d artifactId=spring-api \
-d name=SpringApi \
-d packageName=com.example.springapi \
-o apps/spring-api.zip
# Extract the project
cd apps
unzip spring-api.zip -d spring-api
rm spring-api.zip
cd ..
Step 6: Create Nx Project Configuration
Create apps/spring-api/project.json:
{
"name": "spring-api",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"sourceRoot": "apps/spring-api/src",
"targets": {
"build": {
"executor": "@nx/gradle:gradle",
"outputs": ["{projectRoot}/build"],
"options": {
"taskName": "build"
}
},
"serve": {
"executor": "@nx/gradle:gradle",
"options": {
"taskName": "bootRun"
}
},
"test": {
"executor": "@nx/gradle:gradle",
"outputs": ["{projectRoot}/build/test-results"],
"options": {
"taskName": "test"
}
},
"clean": {
"executor": "@nx/gradle:gradle",
"options": {
"taskName": "clean"
}
}
},
"tags": ["type:app", "platform:jvm"]
}
Step 7: Verify Project Setup
# List all projects
./nx show projects
# Output: spring-api
# Build the project
./nx build spring-api
# Run the application
./nx serve spring-api
Step 8: Create a REST Controller
Create apps/spring-api/src/main/java/com/example/springapi/HelloController.java:
package com.example.springapi;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello from Spring Boot in Nx Monorepo! ๐";
}
@GetMapping("/")
public String home() {
return "Welcome to Spring API - Powered by Nx";
}
}
Step 9: Test Your API
# Start the server
./nx serve spring-api
# In another terminal, test the endpoints
curl http://localhost:8080/hello
# Output: Hello from Spring Boot in Nx Monorepo! ๐
curl http://localhost:8080/
# Output: Welcome to Spring API - Powered by Nx
Step 10: Commit Your Work
git add .
git commit -m "Add Spring Boot API with Nx integration"
Essential Nx Commands
Here are the key commands youโll use regularly:
# Check Nx version
./nx --version
# List all projects
./nx show projects
# Show project details
./nx show project spring-api
# Build a project
./nx build spring-api
# Run/serve a project
./nx serve spring-api
# Run tests
./nx test spring-api
# Clean build artifacts
./nx clean spring-api
# View dependency graph
./nx graph
# Clear Nx cache
./nx reset
# Run command for multiple projects
./nx run-many -t build -p spring-api,another-app
# Show which projects are affected by changes
./nx show projects --affected
# Visualize affected project dependency graph
./nx graph --affected
# Run command only for affected projects
./nx affected -t test
./nx affected -t build
./nx affected -t lint
# Advanced affected commands
# Run affected with specific base branch
./nx affected -t test --base=origin/main
# Run affected comparing to a specific commit
./nx affected -t test --base=HEAD~1
# Dry run (see what would be affected)
./nx affected -t test --dry-run
# Run affected in parallel
./nx affected -t test --parallel=3
# Skip cache for affected
./nx affected -t test --skip-nx-cache
๐ Congratulations!
Youโve successfully completed Series 1 of the Nx Monorepo tutorial!
What Youโve Accomplished
- โ Understanding monorepo architecture used by tech giants
- โ Set up an Nx monorepo from scratch
- โ Installed and configured @nx/gradle plugin
- โ Integrated Spring Boot 3.4 with Java 21
- โ Created REST API endpoints
- โ Successfully built and ran Spring Boot using Nx
Your Spring Boot API is now running in an enterprise-grade Nx monorepo with:
- ๐ Smart caching for faster builds
- ๐ Dependency tracking
- ๐๏ธ Scalable architecture
- ๐ ๏ธ Professional tooling
๐ Coming in Series 2: Full-Stack Development
In the next part of this series, weโll expand our monorepo:
Whatโs Next
- ๐ฑ Adding a React/Next.js Frontend
- ๐ Frontend-Backend Integration
- ๐ฆ Code Sharing Between Projects
- ๐ฏ Running Full-Stack Together
- ๐งช Testing Full-Stack Applications
Teaser Commands
# Coming in Series 2:
./nx add @nx/react
./nx generate @nx/react:application web
./nx run-many -t serve -p spring-api,web
Stay tuned for Series 2! ๐โจ
Additional Resources
Official Documentation
Monorepo Concepts
- Monorepo.tools
- Why Google Stores Billions of Lines of Code in a Single Repository
- Bazel - Googleโs Build Tool
Community
Conclusion
Youโve learned the fundamentals of monorepo architecture and successfully integrated Spring Boot with Nx! This foundation will serve you well as we explore more advanced topics in upcoming series.
Key Takeaways
- ๐๏ธ Monorepos enable better code sharing and consistency
- ๐ Nx provides enterprise-grade tooling
- โ Spring Boot integrates seamlessly via Gradle plugin
- ๐ Tech giants trust monorepo architecture for good reasons
In Series 2, weโll add a frontend application and explore full-stack development in the Nx monorepo!
About This Series
This is Part 1 of the Nx Monorepo Series:
- โ Series 1: Introduction to Nx & Spring Boot Integration (You are here)
- ๐ Series 2: Full-Stack Development with React/Next.js
- ๐ Series 3: Shared Libraries & Code Reuse
- ๐ Series 4: Advanced Nx Features & CI/CD
- ๐ Series 5: Multi-Technology Monorepo
Repository: github.com/kreasipositif/demo-monorepository
Ready to master modern monorepo architecture? Join our comprehensive development courses at Kreasi Positif Indonesia and learn industry best practices from experienced software engineers.