Contact us
Contact us
01. Our Work
01. Our Work
02. About Us
02. About Us
03. Solutions
03. Solutions
04. Our Process
04. Our Process
05. Blog
05. Blog
06. Calculator
06. Calculator

Our offices

  • Tallinn
    Harju maakond, Kesklinna linnaosa, Narva mnt 5
    10117, Tallinn, Estonia
    • +372-623-7083
  • Email
    office@make-it.run

Follow us

  • Work
    • View Our Work
    • Case Studies
    • See all →
  • Company
    • About
    • Solutions
    • Process
    • Blog
    • Calculator
    • Contact us
  • Legal
    • Privacy Policy
    • Terms of Service
  • Connect
    • LinkedIn
    • Facebook
    • Youtube
    • X

Stay updated with make-it.run

Subscribe to get the latest tech insights, startup resources, and development tips from our team.

© make-it.run 2025

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

Aleksandr

By Aleksandr

Published on July 2025

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 management

Why 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.

Top tip

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:

# 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:

# 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:

package.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:

# 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:

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:

# 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:

apps/api/tsconfig.app.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:

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:

# 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:

apps/mobile/app.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:

package.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:

# 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:

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:

package.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:

# 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:

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

# 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

# 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

Top tip

Start simple with your shared libraries. Begin by extracting common TypeScript interfaces and utility functions before moving to complex component sharing between web and mobile platforms.

Troubleshooting Common Setup Issues

React Native Version Conflicts

If you encounter React Native version issues:

# 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:

apps/mobile/metro.config.js

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:

tsconfig.base.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"]
}
GitHub repo:
makeit-run/monorepo-heaven
TypeScript

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.

Tell us about your project

Tell us everything!

Our offices

  • Tallinn
    Harju maakond, Kesklinna linnaosa, Narva mnt 5
    10117, Tallinn, Estonia
    • +372-623-7083
  • Email
    office@make-it.run

Related Posts

Server Components aren't SSR!
June 2025/Blog Post

Server Components aren't SSR!

Anthony
By Anthony
June 2024/Blog Post

10 Proven Ways to Make Next.js Blazing Fast

Anthony
By Anthony