New to Rust? Grab our free Rust for Beginners eBook Get it free →
Understanding Node.js NODE_ENV: A Complete Guide for 2026

If you have ever wondered why your Node.js application behaves differently on your laptop compared to the server it runs on in production, the answer is almost always the same: NODE_ENV. This single environment variable is one of the most powerful levers in your entire Node.js stack, yet I see junior developers treat it as an afterthought all the time. Let me set the record straight because getting NODE_ENV right the first time saves you hours of debugging mysterious production bugs later.
NODE_ENV tells Node.js which mode your application is running in. The three values you will use most are development, test, and production. Each mode changes how the JavaScript runtime and your frameworks behave, sometimes in ways that are not obvious at first. Frameworks like Express, NestJS, and Next.js all read this variable and make decisions based on its value. Those decisions affect performance, security, caching behavior, and how much debug information gets exposed to the outside world.
Here is the thing that trips up a lot of people. You can set NODE_ENV to anything you want. Node.js itself does not enforce it. You could write NODE_ENV=banana and Node.js would happily start up without complaint. What enforces the behavior is your frameworks and libraries. Express has explicit code that checks process.env.NODE_ENV and changes how it operates. Next.js uses it to decide between the dev server and the production build pipeline. NestJS uses it to determine whether to apply certain decorators and guards. The ecosystem has broadly settled on three conventional values, and straying from those conventions means you are fighting the tools instead of working with them.
Think of NODE_ENV like the gear selector in a car. You can technically force a car into reverse while moving forward, and it will grind and protest, but the transmission is designed for Drive, Neutral, and Reverse. NODE_ENV is the same. The ecosystem built its conventions around those three gears. Use them.
TLDR
- NODE_ENV controls how Node.js and your frameworks behave at runtime. Set it to development, test, or production.
- Production mode enables optimizations and disables debug features. Never run a public-facing app in development mode.
- Express behaves differently in each mode. Caching, error handling, and routing all change based on NODE_ENV.
- Docker and Kubernetes both need NODE_ENV set correctly in your containers. A misconfigured container is a security risk.
- When something breaks in production but not locally, NODE_ENV is one of the first things to check.
What NODE_ENV Actually Controls
Let me give you a concrete example of what I mean. Here is a minimal Express server with no NODE_ENV handling at all.
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Hello, world!");
});
app.listen(3000, () => {
console.log("Server running on port 3000");
});
Run this as-is on your local machine. Now set NODE_ENV=production and run it again. You will notice the difference immediately in how Express behaves. In production mode, Express enables view cache, enables gzip compression recommendations at the middleware level, and switches to a more efficient default error handler that does not leak stack traces. The code did not change. Only the environment variable changed.
Here is another way to think about it. NODE_ENV is like the label on a filing cabinet drawer. You can put anything in any drawer, but when someone walks in and sees the label “Tax Returns 2019,” they know exactly what belongs there. Frameworks see the label “production” and apply the correct settings automatically.
The official Node.js documentation does not enforce any specific values for NODE_ENV. That is intentional. Node.js is a runtime, not a web framework. It does not presume what you are building. But the broader ecosystem around it, from Express to Webpack to Next.js, has converged on three conventional values that you should treat as your standard vocabulary.
The Three Environments: Development, Test, and Production
Your application will encounter three distinct environments throughout its lifecycle. Each environment has specific expectations and consequences if you get them wrong.
| Feature | Development | Test | Production |
|---|---|---|---|
| Error stack traces | Shown in browser and console | Captured by test runner | Logged only, never exposed |
| Caching | Disabled or minimal | Disabled for isolation | Full caching enabled |
| Logging verbosity | Verbose, debug-level output | Controlled by test config | Minimal, structured logs only |
| Security headers | May be relaxed for debugging | May be bypassed by test suite | Strict, all headers enforced |
| Performance optimizations | Disabled for easier debugging | May vary by test strategy | Fully enabled |
| Build artifacts | Source maps present | Source maps optional | Minified, source maps stripped |
| Database queries | Raw queries logged | Queries capped by test DB | Optimized queries, pooled connections |
The comparison above makes one thing clear. Development mode prioritizes your ability to debug. Production mode prioritizes security and performance. Test mode prioritizes isolation and repeatability. These three goals are fundamentally at odds with each other, which is exactly why you should never run your production server with NODE_ENV set to development.
How NODE_ENV Affects Express.js Behavior
Express is the most widely used web framework in the Node.js ecosystem. It also happens to be one of the most NODE_ENV-aware frameworks you will encounter. Understanding what changes in Express across environments is essential for anyone building Node.js backends.
In development mode, Express enables verbose error reporting. When an unhandled exception occurs, you get the full stack trace, the file paths, and the line numbers. This is incredibly useful when you are building and debugging. In production mode, Express switches to its production error handler, which logs the error but never sends stack traces to the client. Exposing stack traces in production is a security risk because they reveal your internal file structure, library versions, and sometimes even database query fragments.
Consider this scenario. You are building a REST API and you accidentally have a typo in your route handler that references an undefined variable. In development, Express catches this, builds a helpful error object with the stack trace, and sends it to your Postman or browser with a detailed message. In production, Express logs that same error but returns a generic 500 Internal Server Error to the client. The difference is not a bug. It is a deliberate security feature built into Express that activates when NODE_ENV equals production.
Here is a practical example of how you can leverage NODE_ENV in your own Express middleware.
const isProduction = process.env.NODE_ENV === "production";
app.use((err, req, res, next) => {
if (isProduction) {
// Log the full details for your team to investigate
console.error(err.stack);
// Send a generic message to the client
res.status(500).send("Something went wrong. Please try again later.");
} else {
// In development, be verbose and helpful
res.status(500).send(`Error: ${err.message}\n${err.stack}`);
}
});
That pattern above is something I use in almost every Express project. It costs you nothing and gives you the best of both worlds. You get full debug information locally, and your users in production never see anything that could help an attacker.
Express also handles routing differently. In development, route matching is more forgiving with things like duplicate middleware calls and trailing slashes. In production, the router is stricter because that strictness prevents subtle bugs from slipping through. If your production code has a route that works fine in development but breaks in production, a loose NODE_ENV check should be one of your first debugging steps.
Why Production Mode Is Critical for Security
Let me be direct about this because I have seen the consequences. Running a Node.js application in development mode in a production environment is a security incident waiting to happen. It is not a theoretical risk. Stack traces exposed through verbose error handling have led to real data breaches and privilege escalation vulnerabilities.
Here is a real example of what can go wrong. I once audited a Node.js application where the team had deployed to their production server but forgotten to set NODE_ENV. Express defaulted to its internal behavior, which in older versions would expose full stack traces on 500 errors. An attacker who sent malformed requests to the API could see the exact file paths of the application, the versions of the packages being used, and in some cases even parts of environment variable names. That information alone is enough to look up known CVEs for those package versions and craft a targeted exploit.
The fix took about 10 minutes. They set NODE_ENV=production and restarted the server. The verbose error output stopped immediately. The stack traces were gone. This is not a story I am making up to scare you. This happens in real production environments, especially in small teams where one person handles deployment and they are moving fast.
Beyond Express, many Node.js security-related packages use NODE_ENV to decide what to expose. The Helmet.js middleware for adding security headers to Express applications checks NODE_ENV. If it is not set to production, some security headers are not applied or are applied in a weaker configuration. Helmet is doing this because certain headers like Content-Security-Policy can break development workflows when applied too strictly. The tradeoff is that if you forget to set NODE_ENV, Helmet holds back on you.
Think of production mode like a fire alarm system in a building. In normal operation, you do not hear it and it stays out of your way. But when something goes wrong, it activates and protects everyone. NODE_ENV=production is that fire alarm for your Node.js application. Keep it enabled and you get protection from a whole class of vulnerabilities that you probably are not even thinking about.
Docker and Kubernetes NODE_ENV Patterns
Containers have changed how we think about environment configuration, but NODE_ENV still matters inside your containers. The way you set it differs between development and production workflows, and getting it wrong in a Docker or Kubernetes context has caused real incidents.
In a typical Dockerfile for a Node.js application, you might see something like this.
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
The problem with the Dockerfile above is that it does not set NODE_ENV at all. Your application defaults to undefined behavior. Frameworks like Express treat undefined NODE_ENV similarly to development mode, which means verbose errors and relaxed settings. For a production container, you should explicitly set NODE_ENV to production.
FROM node:22-alpine
ENV NODE_ENV=production
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Setting NODE_ENV=production in the Dockerfile ENV line is the correct approach. Now every process inside that container sees NODE_ENV=production without needing to set it again in your startup command. The package manager also benefits because npm install with NODE_ENV=production skips devDependencies automatically, which makes your production image smaller and faster to build.
In Kubernetes, the picture gets more nuanced. You have multiple layers where NODE_ENV can be configured. You can set it in your Deployment manifest under the env field, or you can rely on the Dockerfile ENV instruction and pass overrides through Kubernetes ConfigMaps. Here is a practical Kubernetes Deployment snippet.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-node-api
spec:
replicas: 3
selector:
matchLabels:
app: my-node-api
template:
metadata:
labels:
app: my-node-api
spec:
containers:
- name: api
image: my-node-api:latest
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: "production"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
One mistake I see in Kubernetes setups is teams setting NODE_ENV in their local development ConfigMap and then forgetting to update the production ConfigMap. Your cluster has separate ConfigMaps for each environment for a reason. Treat them that way. NODE_ENV in a development namespace should remain development so your local engineers can debug against a staging cluster. NODE_ENV in production should always be production.
Here is a useful pattern for managing multiple environments. Use a Kubernetes profile that maps directly to your environment name. Name your ConfigMaps and Secrets after the environment. Your development ConfigMap gets NODE_ENV=development, your staging ConfigMap gets NODE_ENV=staging, and your production ConfigMap gets NODE_ENV=production. Then reference those ConfigMaps in your Deployment using the envFrom field. This approach scales cleanly as you add more services and more environments.
How Framework Configs Tie to NODE_ENV
NODE_ENV is not just an Express thing. Almost every major Node.js framework uses it as a signal to change its internal configuration. Understanding how it interacts with your specific framework will help you avoid surprises when you deploy.
Next.js and NODE_ENV
Next.js is one of the most explicit frameworks when it comes to NODE_ENV. The framework uses it to determine which server to start. When NODE_ENV=development, Next.js runs its dev server with hot module replacement, fast refresh, and detailed build output. When NODE_ENV=production, Next.js runs the production build pipeline, optimizes the JavaScript bundles, and serves the optimized output through a highly tuned server.
Running Next.js with NODE_ENV=production during development is miserable because you lose hot module replacement. Every code change requires a full rebuild and restart. Running Next.js with NODE_ENV=development in production is dangerous because the dev server exposes source maps and detailed error messages that can aid an attacker. The values map to specific use cases and should never be swapped.
Next.js also reads NODE_ENV to configure its caching behavior. In production, Next.js aggressively caches rendered pages, API responses, and static assets. In development, caching is intentionally disabled to ensure developers see their latest changes immediately. This distinction is critical for building performance-optimized applications. If your production Next.js app feels slow, one of the first things to verify is that NODE_ENV is actually set to production.
NestJS and NODE_ENV
NestJS is an opinionated framework built on top of Express or Fastify. It uses NODE_ENV heavily for its internal validation pipes, guards, and interceptors. In development mode, NestJS enables more verbose logging and allows exceptions to bubble up with full metadata. In production mode, NestJS applies its standard output formatting and transforms exceptions into standardized error responses that do not leak internal details.
Here is a practical NestJS example showing how you can conditionally apply a guard based on NODE_ENV.
import { Injectable, CanActivate } from "@nestjs/common";
import { Request } from "express";
@Injectable()
export class DevGuard implements CanActivate {
canActivate(context: any): boolean {
if (process.env.NODE_ENV === "production") {
// In production, deny access to anything protected by this guard
return false;
}
// In development, allow access for debugging purposes
return true;
}
}
I do not recommend the pattern above for actual security controls, but it illustrates how NestJS developers often use NODE_ENV to conditionally enable development-only features. A more realistic example is using NODE_ENV to control logging levels. In development you want to see every incoming request and its parameters. In production you want structured JSON logs with only the information your observability stack cares about.
Webpack and NODE_ENV
Webpack, which powers the build systems of many frameworks including older Next.js versions and Create React App, checks NODE_ENV to determine how to compile your code. When NODE_ENV=development, Webpack produces unminified bundles with source maps and full variable names for easier debugging. When NODE_ENV=production, Webpack minifies your code, removes dead code, strips out debugging statements, and applies tree shaking to reduce bundle size.
Here is a simple Webpack configuration that demonstrates this behavior explicitly.
const isProduction = process.env.NODE_ENV === "production";
module.exports = {
mode: isProduction ? "production" : "development",
devtool: isProduction ? "source-map" : "eval-source-map",
optimization: {
minimize: isProduction,
},
};
Using eval-source-map in production is a serious mistake. It exposes your entire application source code to anyone who opens their browser developer tools. The source maps generated by eval-source-map are not separate files that only your server serves to authorized users. They are embedded directly in the JavaScript served to the browser. Anyone can download your production bundle and immediately have readable source code. Set NODE_ENV to production and let Webpack use proper source-map behavior.
Common Debugging When NODE_ENV Goes Wrong
NODE_ENV bugs are some of the most frustrating issues to debug because the symptoms often have nothing to do with NODE_ENV itself. A function works perfectly in development but throws cryptic errors in production. A database connection works locally but times out on the server. These symptoms have many potential causes, but NODE_ENV is frequently the culprit.
Here is a common scenario. You deploy your Node.js API to a cloud server. The server starts and responds to requests, but your logs are suspiciously verbose. You see debug messages, detailed stack traces, and raw database queries in your logs. You did not intentionally enable debug mode. The most likely explanation is that NODE_ENV is set to development or is not set at all. Check it immediately with a single command.
node -e "console.log("NODE_ENV:", process.env.NODE_ENV)"
If that command returns undefined, you have found your problem. Your application is running in a framework-dependent default state that is probably closer to development than production. Set NODE_ENV explicitly and restart the process.
Another common issue is NODE_ENV caching in Webpack. If you set NODE_ENV in your Webpack config and run the build, the value gets embedded into your bundle. If you later change NODE_ENV without rebuilding, the old value persists. This catches a lot of people off guard because they update their environment variables and restart their server but the application still behaves like it is in development mode. The fix is always to rebuild after changing NODE_ENV.
Here is a debugging checklist I run through whenever I suspect a NODE_ENV issue.
- Run `node -e “console.log(process.env.NODE_ENV)”` directly on the server. Verify the value is what you expect.
- Check your startup command. Make sure NODE_ENV is not being overridden by a shell script or systemd unit file.
- Restart the process after changing NODE_ENV. Node.js reads the variable once at startup and never checks it again.
- If using Docker, verify the ENV directive in your Dockerfile matches your intended environment.
- If using Kubernetes, check your ConfigMap and your Deployment manifest env section for conflicting values.
- Check your package.json scripts. Some npm scripts set NODE_ENV internally and may conflict with your shell environment.
The restart point is particularly important. I have seen developers change NODE_ENV in their shell, run their startup script, and still see development-mode behavior. The reason is that Node.js reads environment variables once when the process starts. If your startup script launches a new shell that then launches Node, the variable may not propagate correctly. Always restart the actual Node.js process after changing NODE_ENV.
Setting NODE_ENV Across Different Platforms
The syntax for setting environment variables varies between operating systems. Here is a quick reference for the three platforms you will encounter most.
On Linux and macOS, you can set NODE_ENV inline with your command.
NODE_ENV=production node server.js
To persist this across shell sessions, add it to your shell profile file. For bash, that is ~/.bashrc or ~/.bash_profile. For zsh, which is the default on modern macOS, it is ~/.zshrc.
echo "export NODE_ENV=production" >> ~/.bashrc
source ~/.bashrc
On Windows, the command is different because Windows uses a different shell syntax. You can use the set command for a single session or setx for a permanent change.
set NODE_ENV=production
For PowerShell users, the syntax is more similar to Linux.
$env:NODE_ENV="production"
In package.json scripts, you can use cross-env to set NODE_ENV in a way that works across all platforms. This is the approach I recommend for any project that has contributors on different operating systems.
{
"scripts": {
"start:dev": "cross-env NODE_ENV=development node server.js",
"start:prod": "cross-env NODE_ENV=production node server.js",
"test": "cross-env NODE_ENV=test jest"
}
}
Installing cross-env is simple.
npm install --save-dev cross-env
Using cross-env means you never have to worry about platform-specific syntax in your npm scripts. Your CI/CD pipeline, your colleague laptop, and your Docker container all run the same scripts and get the same NODE_ENV value.
NODE_ENV and Performance
One of the most immediate effects of NODE_ENV is on your application performance. Switching from development to production mode often produces measurable performance improvements without changing a single line of application code.
Express in production mode enables internal optimizations that are disabled during development. These include faster routing, better memory management for large request bodies, and more efficient session handling. The differences are not massive in absolute terms, but they compound under load. A server handling 1000 requests per second that shaves 5 milliseconds off each request due to production optimizations is saving 5 seconds of CPU time per second of load.
V8 JavaScript engine optimizations also tie into NODE_ENV through the frameworks that use it. When a framework detects production mode, it can enable optimizations like constant propagation and function inlining in its generated code. These are low-level compiler optimizations that reduce function call overhead and improve execution speed. Development mode often disables these to allow for easier debugging and hot reloading.
Here is a simple benchmark you can run yourself to see the difference. Create a basic Express server, run it with NODE_ENV=development, use a load testing tool like autocannon to measure throughput, then repeat with NODE_ENV=production. The numbers will differ, and on a server handling real traffic, the production numbers will almost always be better.
# Run with development mode
NODE_ENV=development node server.js
# In another terminal, run the load test
npx autocannon -c 10 -d 10 http://localhost:3000/
# Then run with production mode
NODE_ENV=production node server.js
# Run the same load test
npx autocannon -c 10 -d 10 http://localhost:3000/
The V8 engine also benefits from a feature called JIT (Just-In-Time) compilation warmup. When your Node.js process starts in production mode, V8 applies a set of optimizations that assume the code will run without restarts for extended periods. Development mode is more conservative because it assumes code will change frequently. A production server that stays up for weeks will eventually run faster than the same server running in development mode for the same duration.
What About Custom NODE_ENV Values
I mentioned earlier that you can technically set NODE_ENV to anything. Let me explain why you might want to take advantage of that, and why you should be cautious about it.
Some teams use NODE_ENV=staging to represent an environment that is between development and production. This is useful when you have a dedicated staging server that mirrors your production configuration but is not publicly accessible. Staging mode lets your frameworks apply a middle tier of settings, where some development conveniences are disabled but full production security is not required because the server is not exposed to the public internet.
Other teams use more specific values like NODE_ENV=preview to represent a deployment preview environment for pull requests. Frameworks like Next.js have built-in support for preview mode because they recognize that preview deployments need some production characteristics like optimized builds but also need some development characteristics like draft content access.
The risk of custom values is that they are not automatically understood by every library in your dependency tree. Some packages check for a specific set of values and fall back to development defaults if they do not recognize the value. If you set NODE_ENV=staging and a package in your dependency tree does not recognize staging, it might silently fall back to development mode without warning. Always test your full stack when using custom NODE_ENV values to verify that all packages behave as expected.
A safer approach is to use custom values only for your own application code and ensure that your deployment infrastructure always sets a recognized value for your dependencies. You can do this by setting NODE_ENV=production in your Dockerfile or Kubernetes manifest, and then using a separate custom variable like APP_ENV=staging for your own application logic.
// In your application code, check both
const isProduction = process.env.NODE_ENV === "production";
const isStaging = process.env.APP_ENV === "staging";
if (isStaging) {
// Apply staging-specific logic
app.use(stagingLogger);
} else if (isProduction) {
// Apply production logic
app.use(productionLogger);
}
This pattern keeps your deployment infrastructure clean while giving you the flexibility to differentiate between multiple deployment targets. Your Dockerfile sets NODE_ENV=production so all third-party packages behave correctly. Your application reads APP_ENV for its own business logic about which environment it is running in.
NODE_ENV and Testing
Testing is where NODE_ENV plays a critical role that many developers overlook. The value you set during testing directly affects how your application behaves, which in turn affects your test results. If your tests pass in development but fail in production, NODE_ENV is often the bridge between those two realities.
When NODE_ENV=test, Node.js and your frameworks optimize for test isolation. Database connections are mocked or pointed at a test database. Caching is disabled so each test gets fresh data. Logging is suppressed or redirected to your test runner output. External HTTP calls are intercepted by tools like nock or msw so your tests never make real network requests.
Here is a Jest configuration that explicitly sets NODE_ENV.
// jest.config.js
module.exports = {
testEnvironment: "node",
setupFiles: ["/test/setup.js"],
};
// test/setup.js
process.env.NODE_ENV = "test";
Jest sets NODE_ENV automatically when it runs your tests. If you are using a different test runner like Mocha, you may need to set it yourself in your test setup file. Failing to set NODE_ENV=test in a Mocha test suite means your application runs in whatever the default state is, which is typically undefined, which most frameworks treat as development mode. Your tests might pass even though they are running against development-mode code, and then fail in production.
One common mistake is running integration tests against a real database without setting NODE_ENV=test. Your application might cache query results in production mode, which means an integration test that creates a record and then tries to read it back immediately might fail because the cache is preventing the fresh read. Set NODE_ENV=test, disable the cache, and your integration tests will behave consistently.
Final Thoughts on NODE_ENV
NODE_ENV is one of those concepts that seems simple on the surface but has depth once you start working with it seriously. The single variable controls an enormous amount of your application behavior, and getting it right is one of the highest-leverage things you can do for your Node.js applications.
My recommendation is to be explicit about NODE_ENV everywhere. Never leave it undefined in production. Never assume it carries over correctly between environments. Verify it at startup and log it so you can audit what your application thinks its environment is. The 30 seconds you spend adding that startup log will save you hours of debugging the next time something behaves differently between your laptop and your server.
If you take one thing away from this article, let it be this. NODE_ENV=production is not optional in production. It is a security-critical configuration that affects error handling, security headers, caching, build output, and framework behavior. Treat it with the same seriousness you treat your authentication system or your database credentials. It belongs in that category of configuration, and it deserves the same level of attention.
Frequently Asked Questions
What is NODE_ENV in Node.js?
NODE_ENV is an environment variable that Node.js and its frameworks use to determine the runtime mode of your application. The conventional values are development, test, and production. Each mode changes how frameworks like Express, Next.js, and NestJS behave, affecting error handling, caching, security headers, and build optimizations.
How do I set NODE_ENV in Node.js?
You can set NODE_ENV inline when running a command, such as NODE_ENV=production node server.js. On Linux and macOS, use the export syntax. On Windows, use the set command. In package.json scripts, use the cross-env package for cross-platform compatibility. In Docker, use the ENV directive in your Dockerfile.
Why does NODE_ENV=production matter for security?
When NODE_ENV is set to production, Express and other frameworks disable verbose error reporting, hide stack traces from clients, and enforce strict security headers. Without NODE_ENV=production, your application exposes internal error details that can help attackers identify vulnerabilities in your stack. This is why setting NODE_ENV explicitly in production is a security requirement, not a suggestion.
What happens if NODE_ENV is not set?
When NODE_ENV is not set, Node.js defaults it to undefined. Most frameworks, including Express, treat undefined NODE_ENV similarly to development mode. This means verbose errors, relaxed security settings, and disabled optimizations. Never deploy to production without explicitly setting NODE_ENV to production.
Does NODE_ENV affect performance?
Yes. Express and other frameworks apply performance optimizations when NODE_ENV=production, including faster routing, better memory management, and more efficient middleware chains. Node.js and the V8 engine also apply JIT optimizations that are more aggressive in long-running production processes. Switching from development to production mode often results in measurable throughput improvements without any code changes.
How do I debug NODE_ENV issues in production?
Start by verifying the actual value of NODE_ENV on your production server using node -e “console.log(process.env.NODE_ENV)”. Check your startup scripts, systemd unit files, Docker ENV directives, and Kubernetes ConfigMaps for conflicting or missing values. Remember that Node.js reads environment variables once at process startup, so you must restart the process after changing NODE_ENV for the change to take effect.
Can I use custom values for NODE_ENV?
Yes, technically. You can set NODE_ENV to any value, but only the conventional values (development, test, production) are automatically understood by all packages in your dependency tree. Custom values like staging or preview work if your own application code handles them, but third-party packages may fall back to development defaults. For custom environments, consider using a separate variable like APP_ENV for your own logic while keeping NODE_ENV=production for your dependencies.




