Last updated: Aug 4, 2025, 11:26 AM UTC

Docker Node Modules Fix - NudgeCampaign v3

Status: Complete
Date: August 3, 2025
Issue: Next.js container failing with "Cannot find module '../server/require-hook'" error
Solution: Selective volume mounting strategy


Problem Analysis

Root Cause

The Docker container was failing to start the Next.js application with the error:

Error: Cannot find module '../server/require-hook'
Require stack:
- /app/node_modules/.bin/next

Contributing Factors

  1. Volume mounting conflict: Mounting .:/app was overriding the container's node_modules
  2. Local node_modules interference: Local node_modules directory was being mounted into container
  3. Anonymous volume ineffective: The /app/node_modules anonymous volume wasn't preserving container dependencies

Solution Implementation

Step 1: Clean Build Environment

# Remove local node_modules and .next directories
rm -rf node_modules .next

Step 2: Create .dockerignore

node_modules
.next
.git
.gitignore
.dockerignore
Dockerfile*
docker-compose*
README.md
.env
.env.local
npm-debug.log
yarn-error.log
.DS_Store
*.log

Step 3: Update Dockerfile.dev

FROM node:20-alpine

# Install dependencies for development
RUN apk add --no-cache libc6-compat git

# Set working directory
WORKDIR /app

# Copy package files first
COPY package.json ./

# Install dependencies (using npm install to regenerate lock file)
RUN npm install

# Copy remaining source code
COPY . .

# Expose port
EXPOSE 3000

# Development command with hot reload
CMD ["npm", "run", "dev"]

Step 4: Selective Volume Mounting Strategy

Instead of mounting the entire directory, selectively mount only the source files:

volumes:
  - ./src:/app/src
  - ./public:/app/public
  - ./next.config.js:/app/next.config.js
  - ./tsconfig.json:/app/tsconfig.json
  - ./tailwind.config.js:/app/tailwind.config.js
  - ./postcss.config.js:/app/postcss.config.js
  - ./.env:/app/.env

Step 5: Environment Variables

Create .env file with required variables:

NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
JWT_SECRET=your-super-secret-jwt-secret-with-at-least-32-characters
DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres

Step 6: Override Package.json Scripts

Use docker-compose command to override hardcoded ports:

command: npx next dev --port 3000

Key Lessons

Lesson 1: Selective Volume Mounting

  • Problem: Mounting entire directory overrides container's node_modules
  • Solution: Mount only source files that need hot reload
  • Benefit: Preserves container dependencies while enabling development

Lesson 2: .dockerignore is Critical

  • Problem: Local node_modules gets copied into image
  • Solution: Use .dockerignore to exclude node_modules
  • Benefit: Clean container environment without local conflicts

Lesson 3: Environment Variable Mounting

  • Problem: Container can't access .env file
  • Solution: Mount .env file as volume
  • Benefit: Easy environment configuration without rebuilding

Lesson 4: Command Overrides for Flexibility

  • Problem: Package.json scripts have hardcoded ports
  • Solution: Override with docker-compose command
  • Benefit: Container-specific configuration without modifying source

Complete Working Configuration

docker-compose.yml (app service)

app:
  build:
    context: .
    dockerfile: Dockerfile.dev
  ports:
    - "3002:3000"
  volumes:
    - ./src:/app/src
    - ./public:/app/public
    - ./next.config.js:/app/next.config.js
    - ./tsconfig.json:/app/tsconfig.json
    - ./tailwind.config.js:/app/tailwind.config.js
    - ./postcss.config.js:/app/postcss.config.js
    - ./.env:/app/.env
  environment:
    - NODE_ENV=development
    - DOCKER_ENV=true
    - NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
    - NEXT_PUBLIC_SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
    - DATABASE_URL=postgresql://postgres:postgres@supabase-db:5432/postgres
  command: npx next dev --port 3000

Verification

Test Commands

# Build the image
docker compose build --no-cache app

# Start the container
docker compose up -d app

# Check logs
docker logs nudgecampaign-mvp-v3-app-1 --tail 30

# Test the application
curl http://localhost:3002

Expected Result

  • Next.js dev server starts successfully
  • Application accessible at http://localhost:3002
  • Hot reload works for mounted source files
  • No node_modules conflicts

Benefits of This Approach

  1. Clean separation: Container dependencies isolated from local environment
  2. Fast development: Hot reload works for source files
  3. Reproducible builds: No local dependency conflicts
  4. Easy debugging: Can modify source files without rebuilding
  5. Environment flexibility: Easy to change configuration via .env

This solution ensures reliable Docker development environment for Next.js applications while maintaining hot reload capability and avoiding node_modules conflicts.