Solving NestJS Module Resolution in Turborepo: The Package.json Fix

Solving NestJS Module Resolution in Turborepo: The Package.json Fix
3 mn read

The Problem

When working with a NestJS application in a Turborepo monorepo, you might encounter this frustrating error:

Cannot find module '@package/nestjs-health' or its corresponding type declarations

This error occurs even when your imports and directory structure seem correct. After much investigation, the solution turned out to be much simpler than expected: properly configuring your package.json.

The Solution: Key Package.json Fields

The key to solving this issue lies in adding specific fields to your package.json. Here’s the critical configuration that fixed the problem:

{
  "name": "@package/nestjs-health",
  "version": "1.0.0",
  "main": "dist/index.js",     // 👈 Critical field
  "types": "dist/index.d.ts",  // 👈 Critical field
  "private": true,
  "scripts": {
    "build": "tsc",            // 👈 Important script
    "dev": "tsc --watch"       // 👈 Important script
  }
}

Let’s break down why each of these fields is important:

1. Main Field

  • Tells Node.js where to find the entry point of your package
  • Must point to the compiled JavaScript file, not the TypeScript source
  • The dist directory is where TypeScript compiler outputs the compiled files

2. Types Field

"types": "dist/index.d.ts"
  • Tells TypeScript where to find type declarations
  • Essential for proper TypeScript integration
  • Must point to the generated .d.ts file

3. Build Scripts

"scripts": {
  "build": "tsc",
  "dev": "tsc --watch"
}
  • build: Compiles TypeScript files
  • dev: Watches for changes and recompiles automatically
  • Essential for development workflow

Why This Works

  1. Proper Module Resolution
    • The main field ensures Node.js can find your compiled code
    • Without this, Node tries to use the source TypeScript files directly
  2. Type Support
    • The types field enables TypeScript to find type declarations
    • Prevents “cannot find module” type errors
  3. Development Workflow
    • Build scripts ensure your code is properly compiled
    • Watch mode keeps compiled files in sync with source changes

Complete Working Configuration

Here’s the full package.json that solved the issue:

{
  "name": "@package/nestjs-health",
  "version": "1.0.0",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "private": true,
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch",
    "format": "bun run format:prettier && bun run format:es",
    "format:prettier": "prettier --write .",
    "format:es": "eslint . --fix",
    "lint": "bun run lint:prettier && bun run lint:typescript && bun run lint:es",
    "lint:typescript": "tsc --noEmit",
    "lint:prettier": "prettier --check .",
    "lint:es": "eslint .",
    "precommit:format": "prettier --write --ignore-unknown"
  },
  "dependencies": {
    "@nestjs/common": "^10.0.5"
  },
  "devDependencies": {
    "@tooling/typescript": "*",
    "@tooling/prettier": "*"
  }
}

Implementation Steps

  1. Update Package.json
cd packages/nestjs-health
# Update package.json with the new fields

2. Build the Package

bun run build
or
npm run build

3. Verify Directory Structure

packages/nestjs-health/
├── dist/
│   ├── index.js
│   ├── index.d.ts
│   └── ...
├── src/
│   └── index.ts
└── package.json

Common Gotchas

  1. Missing dist Directory
    • Ensure TypeScript is actually compiling your files
    • Check your tsconfig.json has correct outDir configuration
  2. Incorrect Paths
    • Double-check the paths in main and types fields
    • Make sure they match your actual file structure
  3. Build Order
    • Ensure your Turborepo pipeline builds packages before apps
    • Add proper dependencies in your turbo.json

Testing the Fix

After applying these changes, you should be able to:

  • Import your package in any app within your monorepo
import { HealthModule } from '@package/nestjs-health';
  • Get proper TypeScript support and auto-completion
  • Have working builds without module resolution errors

Conclusion

While module resolution issues in a Turborepo + NestJS setup can be frustrating, the solution often lies in proper package.json configuration. The key fields (main, types) and proper build scripts ensure that both JavaScript runtime and TypeScript compiler can find and use your code correctly.

Remember: When working with TypeScript packages in a monorepo, always ensure your package.json properly points to the compiled output, not the source files!

Quick Reference

{
  "main": "dist/index.js",     // Points to compiled JS
  "types": "dist/index.d.ts",  // Points to type declarations
  "scripts": {
    "build": "tsc",           // Compiles TypeScript
    "dev": "tsc --watch"      // Development mode
  }
}

This configuration has proven to be the key to solving module resolution issues in NestJS + Turborepo setups.

Leave a Reply

Your email address will not be published. Required fields are marked *

Reading is essential for those who seek to rise above the ordinary.

ABOUT US

The internet as we know is powerful. Its underlying technologies are transformative, but also, there’s a plethora of haphazard information out there.We are here to serve you as a reliable and credible source to gain consistent information

© 2024, cloudiafrica
Cloudi Africa