Setup Dependencies and PNPM Catalogs

Install all project dependencies using pnpm for the Next.js Drizzle SaaS Kit and an introduction to PNPM Catalogs.

Run pnpm install from the project root to install all dependencies across the monorepo. The monorepo uses PNPM Catalogs for consistent dependency versions across packages. Unlike Prisma, Drizzle doesn't require a separate client generation step.

This guide is part of the Next.js Drizzle SaaS Kit installation.

Setup Dependencies

Install all project dependencies using pnpm for the Next.js Drizzle SaaS Kit and an introduction to PNPM Catalogs.

The Next.js Drizzle SaaS Kit uses pnpm as its package manager. PNPM is faster and more efficient than npm or yarn, especially for monorepos.

We use PNPM Catalogs to manage dependencies. This means that we can use the same version of a dependency across all packages in the monorepo.

Versions are defined in the pnpm-workspace.yaml file - and are referenced by their name in the package.json files of each package, followed by catalog: as version specifier.

{
"dependencies": {
"react": "catalog:",
"next": "catalog:"
}
}

We highly recommend reading the PNPM Catalogs documentation to understand how they work and how to use them.

We migrated from standard pnpm workspaces to PNPM Catalogs in early 2025. The result: install times dropped from ~45s to ~18s on CI, and we eliminated version drift issues that caused "works on my machine" bugs across 15+ packages. If you see catalog: in package.json files, that's why.

Install All Dependencies

From the project root directory:

pnpm install

This command will:

  1. Read pnpm-workspace.yaml to identify all packages
  2. Install dependencies for all apps and packages
  3. Create symlinks between workspace packages
  4. Run the postinstall script to fix monorepo configurations
  5. Create a node_modules folder in root and each package

Warnings from PNPM

You may see warnings such as:

Ignored build scripts: core-js-pure, sharp, unrs-resolver.
Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts.

This is by design! We don't want to run scripts from dependencies that are not needed for the project to run properly. This is a security precaution.

Please ignore these warnings.

Understanding What Gets Installed

The installation process installs dependencies for:

Root workspace:

  • Turborepo 2.x for monorepo management
  • Development tools (TypeScript, Prettier, ESLint configs)

apps/web (Main application):

  • Next.js 16
  • React 19
  • Better Auth 1.x for authentication
  • Drizzle ORM 0.45+
  • Tailwind CSS 4
  • React Hook Form
  • Zod validation
  • All internal workspace packages

apps/e2e (Tests):

  • Playwright for E2E testing
  • Test utilities

packages/ (Shared code):

  • Each package has its own dependencies
  • UI components (Shadcn)
  • Database schema and migrations
  • Authentication logic
  • Utilities and configurations

Workspace Packages

The monorepo uses workspace protocol to link packages:

{
"dependencies": {
"@kit/auth": "workspace:*",
"@kit/ui": "workspace:*",
"@kit/database": "workspace:*"
}
}

This means packages reference each other locally, not from npm.

Post-Install Scripts

After dependency installation, several scripts run automatically:

Requirements Check

Verifies you have the minimum Node.js version:

# Runs automatically via preinstall script
pnpm run --filter scripts requirements

What it checks:

  • Node.js version >= 20.10.0
  • Exits with error if version is too old

Manypkg Fix

Automatically fixes common monorepo issues:

# Runs automatically via postinstall script
manypkg fix

What it fixes:

  • Ensures consistent dependency versions across packages
  • Fixes workspace protocol issues
  • Validates package.json files

Updating Dependencies

Update specific package

If you want to update a specific dependency across all packages, you can use the following command:

# Update Next.js across all packages
pnpm up next -r --latest
# Update in specific workspace
pnpm --filter web up next

Check for outdated packages

Sometimes, you may want to check for outdated dependencies across all packages. You can use the following command to do so:

pnpm outdated -r

Adding New Dependencies

Add to root workspace

This should be done rarely, but if you need to add a dependency to the root workspace, you can use the following command:

# Dev dependency in global scope (rarely needed in root workspace)
pnpm add -D -w <package-name>
# Production dependency in global scope (rarely needed in root workspace)
pnpm add -w <package-name>

Add to specific app/package

If you want to add a dependency to a specific app or package, you can use the following command:

# Add to web app
pnpm --filter web add <package-name>
# Add to @kit/ui package
pnpm --filter @kit/ui add <package-name>
# Add dev dependency
pnpm --filter web add -D <package-name>

Examples

# Add a UI library to web app
pnpm --filter web add framer-motion
# Add a dev tool to all packages
pnpm add -D -r eslint-plugin-custom
# Add to specific package
pnpm --filter @kit/auth add jose

Dependency Management Best Practices

Keep dependencies up to date

# Check for updates weekly
pnpm outdated -r

Use workspace protocol for internal packages

{
"dependencies": {
"@kit/ui": "workspace:*"
}
}

Pin versions for critical dependencies

{
"dependencies": {
"next": "16.0.0" // Exact version
}
}

Use catalog for shared dependencies

This project uses catalog versioning for consistent versions:

{
"dependencies": {
"react": "catalog:",
"next": "catalog:"
}
}

Versions are defined in pnpm-workspace.yaml file in the root of the project.

Common Pitfalls

  • Using npm or yarn - The workspace configuration requires pnpm; other package managers will fail to resolve workspace dependencies
  • Outdated pnpm version - Run pnpm --version to verify you have a recent version (10.x recommended)
  • Conflicting global packages - If you have globally installed packages that conflict, try pnpm install --shamefully-hoist as a last resort
  • Lock file conflicts - If you see lock file conflicts after pulling updates, delete pnpm-lock.yaml and run pnpm install to regenerate it

Next: Project Setup →