Passing NODE_ENV to docker to run package.json scripts
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When a Node.js application changes behavior based on NODE_ENV, the important question in Docker is where that variable should be set. The answer depends on whether you need the value during image build, during container runtime, or both, because Docker treats build-time and runtime configuration as separate scopes.
Set NODE_ENV at Runtime for Script Behavior
If the goal is to control how npm run ... behaves inside a running container, the cleanest place is usually the runtime environment.
This passes NODE_ENV=development into the container process. The script can then read it through process.env.NODE_ENV.
A small diagnostic script makes this easy to verify.
Then run:
That should print staging.
Use ENV in the Dockerfile for a Default
If you want the image to have a default runtime value, set it in the Dockerfile.
This gives the container a baseline value, but docker run -e NODE_ENV=... can still override it at runtime.
That is usually what you want: a production-safe default that can be replaced explicitly in development or staging.
Understand Build-Time Versus Runtime Scope
A frequent source of confusion is expecting a build argument to keep affecting the running container automatically. ARG and ENV are not the same thing.
Build with:
ARG exists only during image build unless you copy it into ENV. If the variable only matters to the running application, a plain runtime environment variable is usually simpler.
Docker Compose Is Better for Team Workflows
For repeatable local development and staging setups, Docker Compose or another orchestrator is usually better than remembering long docker run commands.
This keeps environment configuration declarative and visible to the team.
If the project uses several services, Compose also prevents subtle drift where one container gets the right environment and another silently uses the Dockerfile default.
The same explicitness helps in CI. When a pipeline fails, it is much easier to reproduce locally if the source of NODE_ENV is visible in Compose or the runner command instead of being implied indirectly.
Be Explicit About Dependency Installation
NODE_ENV is often treated as if it automatically solves dependency installation behavior, but it is better to make build intent explicit.
This is clearer than hoping the right NODE_ENV side effect will produce the dependency tree you want. Explicit install commands are easier to audit and less surprising across environments.
Common Pitfalls
The most common mistake is setting NODE_ENV only at build time and expecting a later runtime container to inherit dynamic behavior automatically. Another is assuming a host shell variable is passed into the container without an explicit -e flag or Compose configuration.
Teams also often mix build defaults, Dockerfile ENV, Compose overrides, and ad hoc command-line overrides without documenting which one is authoritative.
Finally, NODE_ENV is not a secret. It describes environment mode, not sensitive configuration. Database passwords and tokens belong in dedicated secret or environment mechanisms, not overloaded into this variable.
Summary
- Use runtime environment variables when
NODE_ENVcontrols how package scripts run inside the container. - Use Dockerfile
ENVonly for sensible defaults. - Use
ARGonly for build-time needs unless you intentionally copy it intoENV. - Prefer Compose or orchestrator config for repeatable team setups.
- Keep dependency-install rules explicit instead of relying on
NODE_ENVside effects alone.

