Skip to main content

Introduction To The Monorepo

What is a Monorepo?

A monorepo (monolithic repository) is a software development strategy where multiple related projects, packages, and applications are stored in a single version control repository. Unlike a multi-repo approach where each project has its own repository, a monorepo centralizes all code in one place while maintaining logical separation between different components.

Key Characteristics of Monorepos

  • Single Source of Truth: All code, documentation, and configurations live in one repository
  • Shared Dependencies: Common libraries and tools are shared across projects
  • Atomic Changes: Cross-project changes can be made in a single commit
  • Unified Tooling: Consistent build, test, and deployment processes
  • Better Collaboration: Teams can easily see and coordinate changes across projects

How This Monorepo Works

Our nextjs-web monorepo is specifically designed to manage multiple Next.js applications and shared packages efficiently. Here's how the key components work together:

Repository Structure

nextjs-web/
├── apps/ # Multiple Next.js applications
│ ├── beacon-docs/ # Beacon design system documentation (Docusaurus)
│ ├── client-central/ # Client management system
│ ├── client.schwab.com/ # Client portal application
│ ├── docs/ # Technical documentation (this site)
│ ├── meganav-mfe/ # Mega navigation micro-frontend
│ ├── nextapi.schwab.com/ # API services
│ ├── nexttools.schwab.com/# Internal development tools
│ ├── sanity-next/ # Sanity CMS demo Next.js app (POC)
│ ├── sanity-studio/ # Sanity CMS admin interface
│ ├── storybook/ # Component library documentation
│ └── www.schwab.com/ # Main public website
├── packages/ # Shared libraries and utilities
│ ├── cli/ # Command-line tools
│ ├── fetch/ # HTTP client utilities
│ ├── mock-data/ # Test data and mocks
│ ├── processors/ # Data processing utilities
│ ├── schema/ # Data schemas and validation
│ ├── security/ # Security utilities and middleware
│ ├── server-actions/ # Next.js server actions
│ ├── test/ # Testing utilities and setup
│ ├── transformer/ # Code transformation utilities
│ ├── tsconfig/ # TypeScript configurations
│ ├── twconfig/ # Tailwind CSS configurations
│ ├── ui/ # React component library
│ └── utilities/ # Common utility functions
└── package.json # Root workspace configuration

Package Management with pnpm

We use pnpm workspaces to manage dependencies across the monorepo:

  • Shared Dependencies: Common packages like React and Next.js are deduplicated
  • Workspace Protocol: Internal packages reference each other using workspace:*
  • Efficient Storage: pnpm's content-addressable storage reduces disk usage
  • Fast Installs: Symlinks and hard links make installations lightning-fast

Build Orchestration with Turbo

Turborepo handles the complex task of building multiple interdependent packages:

  • Dependency Graph: Automatically determines build order based on package dependencies
  • Incremental Builds: Only rebuilds packages that have changed or depend on changed packages
  • Parallel Execution: Builds multiple packages simultaneously when possible
  • Intelligent Caching: Caches build outputs to skip redundant work

Integration with Vercel and Next.js

Our monorepo is optimized for deployment on Vercel with multiple Next.js applications:

Vercel Monorepo Support

Vercel provides first-class support for monorepos through:

  1. Project Configuration: Each application in /apps can be deployed as a separate Vercel project
  2. Build Detection: Vercel automatically detects Next.js applications and configures appropriate build settings
  3. Turbo Integration: Native support for Turborepo caching and build orchestration
  4. Environment Variables: Application-specific environment management

Next.js Application Architecture

Each Next.js application in our monorepo:

  • Independent Deployment: Can be deployed separately with its own domain and configuration
  • Shared Components: Imports UI components from @schwab/ui package
  • Common Utilities: Uses shared utilities for consistent functionality
  • Unified Styling: Shares Tailwind CSS configurations via @schwab/twconfig

Build and Deployment Flow

  1. Change Detection: When code changes, Turbo identifies affected packages
  2. Dependency Resolution: Builds packages in the correct order based on dependencies
  3. Application Building: Next.js applications are built with updated dependencies
  4. Deployment: Vercel deploys only the applications that need updates

Benefits in Our Context

For Development Teams

  • Code Reuse: Shared components and utilities reduce duplication
  • Consistent Standards: Unified linting, formatting, and TypeScript configurations
  • Cross-Application Features: Easy to implement features spanning multiple applications
  • Simplified Dependencies: Single package.json manages all external dependencies

For Deployment and Operations

  • Atomic Releases: Related changes across applications can be deployed together
  • Simplified CI/CD: Single pipeline handles multiple applications
  • Version Synchronization: Ensures all applications use compatible dependency versions
  • Reduced Infrastructure: Fewer repositories to manage and secure

For Next.js Specifically

  • Shared Next.js Configuration: Common configurations in next.config.js files
  • Component Library: Shared React components with consistent styling
  • API Route Sharing: Common API utilities and middleware
  • Performance Optimization: Shared bundles and optimized builds

Getting Started

To work with this monorepo effectively:

  1. Install Dependencies: pnpm install at the root installs all dependencies
  2. Development: Use pnpm dev-[app-name] to start specific applications
  3. Building: Use pnpm build to build all applications, or target specific ones
  4. Testing: Run pnpm test to execute tests across all packages

Development Environment Setup

Schwab Scripts Directory (/home/schwab-scripts)

The monorepo development environment includes a dedicated scripts directory at /home/schwab-scripts that contains essential setup and maintenance scripts for the containerized development environment. These scripts automate the complex configuration required for working within Schwab's corporate infrastructure.

Key Components

  • Container Setup: Automated environment initialization and configuration
  • Git Configuration: Corporate SSL certificates, authentication, and repository setup
  • Package Manager Setup: PNPM configuration for internal registries and proxy settings
  • Quality Gates: Git hooks enforcing code quality standards before commits and pushes
  • Utility Scripts: Port cleanup and maintenance tools

Integration with Monorepo

The scripts in /home/schwab-scripts are specifically designed to work with this monorepo:

  1. Repository Cloning: Automatically clones the nextjs-web repository with proper authentication
  2. Dependency Installation: Runs pnpm install to set up all monorepo dependencies
  3. Git Hooks Installation: Installs quality gate hooks that run Turborepo commands:
    • Pre-commit: Branch name validation
    • Pre-push: Linting, type checking, conformance, testing, and building
  4. Development Server Support: Includes utilities for managing development server ports

Corporate Environment Integration

These scripts handle the complex corporate environment requirements:

  • Proxy Configuration: Supports both ZScaler and BlueCoast proxy setups
  • SSL Certificates: Configures Schwab's internal SSL certificates for secure connections
  • Internal Registries: Configures access to Schwab's private npm registries for @schwab packages
  • Authentication: Handles GitHub tokens and internal registry authentication

For detailed information about these scripts, see the Startup Scripts documentation.

This monorepo structure, combined with the automated setup scripts, enables our team to maintain multiple Next.js applications efficiently while ensuring consistency, code reuse, and streamlined deployment processes through Vercel's platform.