Public Hoist Pattern for MUI in pnpm Monorepos

When you have multiple packages in a pnpm monorepo that all use MUI, you can end up with duplicate MUI instances. This causes bundle bloat and can lead to subtle bugs. Here's how to use pnpm's public-hoist-pattern to share a single MUI instance across all packages.

The Problem

In a monorepo with multiple apps, each package might declare its own MUI dependencies:

apps/
  admin/
    package.json  # @mui/material: ^7.0.0
  worker/
    package.json  # @mui/material: ^7.0.0
packages/
  ui/
    package.json  # @mui/material: ^7.0.0

This leads to:

The Solution

Use pnpm's public-hoist-pattern to hoist MUI packages to the root, making a single instance available to all packages.

1. Configure .npmrc

Create or update .npmrc at the monorepo root:

public-hoist-pattern[]=@mui/*

This tells pnpm to hoist all @mui/* packages to the root node_modules, making them accessible to all workspace packages.

2. Add MUI to Root package.json

Declare MUI dependencies only in the root package.json:

{
  "dependencies": {
    "@mui/icons-material": "^7.3.6",
    "@mui/lab": "7.0.1-beta.20",
    "@mui/material": "^7.3.6",
    "@mui/material-nextjs": "^7.3.6",
    "@mui/x-data-grid-pro": "^8.23.0",
    "@mui/x-date-pickers": "^8.23.0"
  }
}

Usage in Packages

Import MUI as normal. The imports resolve to the hoisted instance:

// packages/ui/src/components/Button.tsx
import Button from '@mui/material/Button';
import IconButton from '@mui/material/IconButton';
import ContentCopy from '@mui/icons-material/ContentCopy';

Benefits

  1. Single Instance: One version of MUI across the entire monorepo
  2. Version Consistency: No mismatches between packages
  3. Easy Upgrades: Update once in root, applies everywhere
  4. Simpler Dependency Management: Only manage MUI versions in one place

Extending the Pattern

You can hoist other shared packages too:

public-hoist-pattern[]=@mui/*
public-hoist-pattern[]=@toolpad/*
public-hoist-pattern[]=@emotion/*