Node.js and TypeScript Workspace Configuration

Introduction

Modern Node.js applications often use monorepos with multiple workspaces and TypeScript for type safety. This section covers configuring Node.js/TypeScript environments in DevContainers with proper workspace root resolution, package manager selection, and linker configuration.

Sections

1. Node.js Version Management

Install Node.js via devcontainer.json features with explicit version pinning (e.g., 18.17.0). Avoid floating major versions (18.x) to prevent silent runtime changes.

Define NODE_HOME and PATH to ensure DevContainer Node.js is preferred over host-level installations. Use NVM only for local development—avoid in containers.

2. Package Manager Selection & Lockfiles

Choose a package manager: npm (default), yarn, or pnpm. Commit lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml) to Git for deterministic resolution.

Configure packageManager in package.json to enforce consistent usage across team. Use exact versions in devcontainer.json to match CI environments.

3. TypeScript Workspace Configuration

Define tsconfig.json with explicit rootDir, outDir, and declaration settings. Use mapFiles in workspace configurations to support multi-package builds.

Configure VS Code typescript.tsdk setting to use workspace-local TypeScript version. This prevents version mismatches between local and remote servers.

4. Monorepo Structure & Builder Integration

Use workspaces (npm workspaces, yarn workspaces) to manage multiple packages. Define workspaceRoot in devcontainer.json to resolve workspace paths correctly.

Configure build pipelines to respect workspace dependencies. Use npm run build --workspaces for parallel builds.

Code Blocks

devcontainer.json with Node.js/TypeScript

{
  "image": "mcr.microsoft.com/devcontainers/javascript-node:18.17.0",
  "mounts": [
    "source=npm-cache,target=/root/.npm,type=volume"
  ],
  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint@3.0.10",
        "esbenp.prettier-vscode@10.1.0"
      ],
      "settings": {
        "typescript.tsdk": "node_modules/typescript/lib",
        "typescript.enablePromptUseWorkspaceTsdk": true
      }
    }
  },
  "postCreateCommand": "npm ci && npm run build"
}

tsconfig.json for workspaces

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node",
    "resolveJsonModule": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

package.json with workspace configuration

{
  "name": "@monorepo/root",
  "version": "1.0.0",
  "packageManager": "npm@10.0.0",
  "workspaces": [
    "packages/*",
    "apps/*"
  ],
  "scripts": {
    "build": "npm run build --workspaces",
    "test": "npm run test --workspaces",
    "lint": "eslint . --fix"
  }
}

Common Pitfalls

  • Floating Node.js versions: Using latest or alpha tags causes runtime incompatibilities. Always pin exact semver.
  • Mismatched package managers: Running npm install in a yarn workspace or vice versa corrupts lockfiles. Enforce package manager via packageManager field.
  • Missing workspace root: Defining workspaceRoot incorrectly breaks monorepo builds. Test builds in fresh containers to validate.
  • Local TypeScript divergence: Not committing TypeScript version causes IDE/CLI mismatches. Always pin typescript in package.json.

FAQ

How do I ensure Node.js/TypeScript consistency across CI and local? Commit package-lock.json and tsconfig.json to Git. Use identical Node.js versions in CI and DevContainers. Run npm ci (not npm install) to respect lock files.

Should I use npm, yarn, or pnpm in containers? npm is default and widely supported. yarn and pnpm offer performance benefits but require explicit installation. Choose based on team preference—consistency matters more than choice.