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
- Volume mounting conflict: Mounting
.:/appwas overriding the container's node_modules - Local node_modules interference: Local node_modules directory was being mounted into container
- Anonymous volume ineffective: The
/app/node_modulesanonymous 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
- Clean separation: Container dependencies isolated from local environment
- Fast development: Hot reload works for source files
- Reproducible builds: No local dependency conflicts
- Easy debugging: Can modify source files without rebuilding
- 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.