Complete Guide to Setting Up NX + Next.js + Expo Project: Modern Monorepo Architecture. Part 1


Complete Guide to Setting Up NX + Next.js + Expo: Modern Cross-Platform Monorepo
Building modern applications often requires managing multiple platforms simultaneously: web applications, mobile apps, and backend APIs. NX provides the perfect foundation for this challenge by offering a monorepo architecture that enables code sharing, consistent tooling, and optimized build processes across web, mobile, and server applications. This comprehensive guide will walk you through creating a production-ready NX workspace that combines Next.js for web development and Expo for cross-platform mobile apps.
What You'll Master
NX workspace creation with cross-platform architecture Next.js application setup with App Router and Tailwind CSS NestJS API configuration for backend services Expo mobile app integration with React Native 0.79+ Optimal project structure for web and mobile code sharing Development workflow optimization and package managementWhy Choose NX for Cross-Platform Development?
The combination of NX with Next.js and Expo addresses the fundamental challenge of modern app development: building for multiple platforms without duplicating business logic, UI components, or development processes. NX provides intelligent dependency management, affected change detection, and build optimization, while Next.js delivers server-side rendering and modern React features for web, and Expo enables native mobile development with React Native.
NX version 21+ introduces enhanced cross-platform support with improved task inference and better dependency graph visualization. This reduces configuration overhead while maintaining complete control over your build pipeline.Prerequisites and Installation
Before creating your cross-platform NX workspace, ensure you have the following tools installed:
bash
# Check Node.js version (18+ recommended)
node --version
# Check npm version
npm --version
# Install NX CLI globally for workspace management
npm i -g nx
For mobile development, you'll also need:
- iOS Development: Xcode (macOS only)
- Android Development: Android Studio and Android SDK
- Expo CLI: Will be installed automatically with the Expo plugin
Creating Your Cross-Platform NX Workspace
Step 1: Initialize Empty NX Workspace
Start with an empty workspace to have complete control over the architecture and gradually add applications as needed:
bash
# Create empty workspace with maximum flexibility
npx create-nx-workspace@latest
Follow the interactive prompts:
- Where would you like to create your workspace? →
monorepo-heaven
- Which stack do you want to use? →
none
- Would you like to use Prettier for code formatting? →
Yes
- Which CI provider would you like to use? →
skip
- Would you like remote caching to make your build faster? →
skip
Step 2: Clean Up Package Configuration
After workspace creation, remove the default workspaces configuration that may conflict with NX's dependency management:
json
{
"name": "monorepo-heaven",
"version": "0.0.0",
"license": "MIT",
"scripts": {},
"private": true,
"devDependencies": {
"nx": "21.3.2",
"prettier": "^2.6.2"
}
// Remove this section:
// "workspaces": [
// "packages/*"
// ]
}
This ensures NX handles all workspace management and prevents package resolution conflicts.
Setting Up Next.js Web Application
Installing Next.js Plugin
Add Next.js support to your NX workspace with the official plugin:
bash
# Navigate to your workspace
cd monorepo-heaven
# Add Next.js plugin
nx add @nx/next
# Generate Next.js application
nx g @nx/next:app apps/web
Configure your Next.js application with these options:
- Which stylesheet format would you like to use? →
tailwind
- Which linter would you like to use? →
eslint
- What unit test runner should be used? →
none
- Which E2E test runner would you like to use? →
none
- Would you like to use the App Router (recommended)? →
true
- Would you like to use
src/
directory? →true
Understanding the Generated Web Structure
After generation, your Next.js application will have a modern structure optimized for the App Router:
bash
apps/web/
├── src/
│ └── app/
│ ├── globals.css # Global styles with Tailwind
│ ├── layout.tsx # Root layout component
│ └── page.tsx # Home page component
├── public/ # Static assets
├── next.config.js # Next.js configuration with NX integration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
└── project.json # NX project configuration
This structure provides the minimum viable setup for a production-ready Next.js application within an NX workspace.
Setting Up NestJS Backend API
Installing NestJS Plugin
Add robust backend API capabilities with NestJS:
bash
# Add NestJS plugin
nx add @nx/nest
# Generate NestJS application
nx g @nx/nest:application apps/api
Configure your API with these selections:
- Which linter would you like to use? →
eslint
- Which unit test runner would you like to use? →
none
Critical NestJS Configuration Fix
The generated NestJS configuration requires a module system update for proper compatibility:
json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "NodeNext",
"types": ["node"],
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"target": "es2021"
},
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*"]
}
The key change is setting "module": "NodeNext"
which ensures proper ES module compatibility and prevents runtime errors.
API Structure Overview
Your NestJS API will be generated with a clean, scalable structure:
bash
apps/api/
├── src/
│ ├── app/
│ │ ├── app.controller.ts # Main API controller
│ │ ├── app.module.ts # Root application module
│ │ └── app.service.ts # Business logic service
│ └── main.ts # Application bootstrap
├── tsconfig.app.json # TypeScript configuration
├── tsconfig.json # Base TypeScript config
└── project.json # NX project configuration
Setting Up Expo Mobile Application
Installing Expo Plugin
Add cross-platform mobile development capabilities:
bash
# Add Expo plugin for React Native development
nx add @nx/expo
# Generate Expo application
nx g @nx/expo:app apps/mobile
Essential Expo Configuration
Update your Expo configuration to enable modern React Native features:
json
{
"expo": {
"name": "Mobile",
"slug": "mobile",
"version": "1.0.0",
"orientation": "portrait",
"newArchEnabled": true,
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
}
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
The critical addition is "newArchEnabled": true
, which enables React Native's New Architecture for better performance and future compatibility.
Updating React Native Dependencies
The default NX Expo template includes outdated React Native packages. Update to the latest stable versions for optimal performance and compatibility:
json
{
"dependencies": {
"react-native": "0.79.2",
"react-native-svg": "15.11.2",
"expo": "^53.0.9",
"expo-splash-screen": "~0.30.8",
"expo-status-bar": "~2.2.3"
},
"devDependencies": {
"react-native-svg-transformer": "1.3.0",
"@expo/metro-config": "~0.20.0",
"@expo/metro-runtime": "~5.0.4"
}
}
After updating dependencies, run the installation:
bash
# Install updated dependencies
npm install
# Clear any existing caches
npx nx reset
Mobile Application Structure
Your Expo application will have a structure optimized for cross-platform development:
bash
apps/mobile/
├── src/
│ └── app/
│ └── App.tsx # Main mobile application component
├── assets/ # Mobile-specific assets
├── app.json # Expo configuration
├── metro.config.js # Metro bundler configuration
├── tsconfig.json # TypeScript configuration
└── project.json # NX project configuration
Optimizing Development Workflow
Adding Convenient NPM Scripts
Enhance your development experience by adding convenient scripts to your root package.json
:
json
{
"name": "monorepo-heaven",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"web:dev": "npx nx dev web",
"api:dev": "npx nx serve api",
"mobile:dev": "npx nx serve mobile",
"build:all": "npx nx run-many --target=build --all",
"lint:all": "npx nx run-many --target=lint --all",
"graph": "npx nx graph"
},
"private": true,
"devDependencies": {
"nx": "21.3.2",
"prettier": "^2.6.2"
}
}
Now you can run your applications with simple commands:
bash
# Start web development server
yarn web:dev
# Start API development server
yarn api:dev
# Start mobile development with Expo
yarn mobile:dev
# Build all applications
yarn build:all
# View dependency graph
yarn graph
Understanding Your Workspace Structure
Your completed NX workspace now has a clean, scalable architecture:
bash
monorepo-heaven/
├── apps/
│ ├── web/ # Next.js web application
│ ├── api/ # NestJS backend API
│ └── mobile/ # Expo mobile application
├── libs/ # Shared libraries (empty for now)
├── tools/ # Custom scripts and configurations
├── nx.json # NX workspace configuration
├── package.json # Root package management
└── tsconfig.base.json # Base TypeScript configuration
Development Commands Reference
Application-Specific Commands
bash
# Web application commands
nx dev web # Start development server
nx build web # Build for production
nx lint web # Lint web application
# API application commands
nx serve api # Start API development server
nx build api # Build API for production
nx lint api # Lint API code
# Mobile application commands
nx serve mobile # Start Expo development server
nx build mobile # Build mobile application
nx lint mobile # Lint mobile code
Workspace-Wide Commands
bash
# Multi-project operations
nx run-many --target=build --all # Build all applications
nx run-many --target=lint --all # Lint all projects
nx affected:build # Build only affected projects
nx affected:test # Test only affected projects
# Workspace management
nx graph # View dependency graph
nx reset # Clear NX cache
nx report # Generate workspace report
Next Steps and Architecture Planning
With your foundational NX workspace established, you're ready to build scalable cross-platform applications. The next phase involves:
Immediate Development Tasks
- Create shared component libraries for code reuse between web and mobile
- Implement API endpoints in your NestJS application
- Set up state management and data fetching patterns
- Configure shared TypeScript types across all applications
Advanced Architecture Considerations
- Design a shared UI component system that works across platforms
- Implement authentication and authorization across web and mobile
- Set up shared business logic libraries
- Configure deployment pipelines for each platform
Troubleshooting Common Setup Issues
React Native Version Conflicts
If you encounter React Native version issues:
bash
# Clear all caches and reinstall
rm -rf node_modules
npm cache clean --force
npm install
# Reset NX cache
npx nx reset
Metro Bundler Configuration
For mobile development issues, ensure your Metro config is properly set up:
javascript
const { getDefaultConfig } = require('@expo/metro-config');
const { withNxMetro } = require('@nx/expo');
const defaultConfig = getDefaultConfig(__dirname);
module.exports = withNxMetro(defaultConfig, {
// NX configuration options
watchFolders: [],
});
TypeScript Configuration Issues
Ensure all applications can resolve shared types by verifying your base TypeScript configuration:
json
{
"compileOnSave": false,
"compilerOptions": {
"rootDir": ".",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es2015",
"module": "esnext",
"lib": ["es2020", "dom"],
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {}
},
"exclude": ["node_modules", "tmp"]
}
Conclusion
You've successfully created a powerful foundation for cross-platform development using NX, Next.js, and Expo. This setup provides a scalable monorepo architecture that enables code sharing between web and mobile applications while maintaining the flexibility to optimize each platform independently.
The workspace you've built includes modern development tools, optimized build processes, and a clean project structure that will grow with your application's complexity. With Next.js powering your web experience, NestJS handling your backend API, and Expo enabling cross-platform mobile development, you have all the essential pieces for building comprehensive modern applications.
In the next part of this series, we'll dive deep into creating shared libraries, implementing cross-platform components, and establishing data flow patterns that maximize code reuse while maintaining platform-specific optimizations. The foundation you've established here will serve as the launching point for building sophisticated, maintainable applications that deliver exceptional user experiences across all platforms.
This post was originally published on make-it.run.
Subscribe to my newsletter
Read articles from Devops Make It Run directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
