Understanding Docker Port Mapping for a Next.js Application

Learn how ports work in a Dockerised Next.js setup with package.json, Dockerfile, and docker-compose.


๐Ÿ” Overview

This guide explains how port configurations work in a Dockerised Next.js project. You'll understand the relationship between:

  • The port defined in package.json
  • The internal port exposed via the Dockerfile
  • The host-to-container mapping in docker-compose

Getting these right ensures smooth development and debugging experiences.


โœ… Key Components and Their Roles

ComponentExampleRoleMust Match?
package.json"start": "next start -p 3001"Defines internal port Next.js listens toโœ… Yes
DockerfileEXPOSE 3001Declares internal port for documentation/toolsโš ๏ธ Recommended only
docker-composeports: ["4001:3001"]Maps host (4001) โ†’ container (3001)โŒ No โ€” host flexible

๐Ÿง  How It Works (Step-by-Step)

  1. Next.js starts inside the container
"start": "next start -p 3001"

This defines the internal port your app binds to.

  1. Dockerfile declares EXPOSE 3001 EXPOSE 3001 This is only for documentation/tooling purposes. It does not affect the appโ€™s behaviour.
  2. docker-compose maps host to container
ports:
  - "4001:3001"

Requests to http://localhost:4001 on the host are forwarded to port 3001 inside the container.

Example Scenario

package.json

"start": "next start -p 3001"

Dockerfile

EXPOSE 3001

ocker-compose.dev.yaml

ports:
  - "4001:3001"

Behaviour

Access PointWhat It Does
localhost:4001Entry point on host
container:3001Where app is actually running
โ†’ ResultDocker forwards โ†’ App responds

๐Ÿ“Œ Note on NEXT_PUBLIC_PORT

  • NEXT_PUBLIC_PORT is for frontend/browser use only.
  • It does not affect backend/server port binding.
  • Always use -p flag in next start to control server port.

๐Ÿงช Common Pitfall

ConfigurationResult
next start -p 3002 + ports: "4001:3001"โŒ Mismatch โ€” Browser fails
next start -p 3002 + ports: "4001:3002"โœ… Works

  • Use a consistent internal port across the stack:
"start": "next start -p 3001"
EXPOSE 3001
ports:
  - "${HOST_PORT:-4001}:3001"
  • Inject NEXT_PUBLIC_PORT=${HOST_PORT} into .env to let your frontend build dynamic URLs correctly.

๐Ÿงพ Conclusion

  • next start -p xxx: Defines app's internal port
  • EXPOSE xxx: Optional for documentation/tooling
  • docker-compose ports: Maps host โ†” container
  • NEXT_PUBLIC_PORT: Only for frontend use

With this knowledge, you'll avoid misconfigurations and ensure consistent behaviour across environments.