# NODE_ENV=production is a lie [eng]
In the beginning, there were configuration files. Each environment had one committed to our repositories. Then, we discovered the light of the 12-factor applications and having environment-specific values set as environment variables. Then, NODE_ENV came along, and it broke our idyllic world.
Libraries with millions of weekly downloads check for NODE_ENV=production to enable optimizations, changing the behavior of applications. Given this worked so well, developers started loading configuration files (or secrets) based on the value of NODE_ENV to identify _their_ "production" environment.
However, what value should be used for the staging environment? What about QA? If we don't run the same code everywhere, we will be hit by bugs that we cannot reproduce across environments. So, we set NODE_ENV=production everywhere. How should we distinguish across environments, then?
- Co-Founder and CTO of Platformatic.dev
- Member of the Node.js Technical Steering Committee focusing on streams, diagnostics and http
- He is also the author of the fast logger Pino and of the Fastify web framework
- Matteo is an renowed international speaker after more than 60 conferences
- Twitter, LinkedIn, YouTube, Twitch
Hi everyone! I'm Mateo Kalina, Platformatic's co-founder and CTO. Today, I'm going to discuss non-underscored AMP. But before we delve into that, allow me to introduce myself. I am also the namesake of the platform. I serve as a member of the Node.js technical steering committee and as a board member of the OpenJS Foundation. I have contributed numerous modules to NPM and oversee a newsletter titled Node.land of the Heaven. More significantly, my software has been downloaded 17 billion times last year alone, excluding Node, indicating widespread usage.
Now, let's address Node.env and its significance. Node.env is a widely used variable that holds considerable importance. However, it is also a source of significant semantic confusion within the industry. "Env" typically stands for environment, but what precisely constitutes an environment? According to software deployment standards, an environment or tier refers to a computer system or set of systems where a software program or component is deployed and executed.
When discussing environments, it's essential to distinguish between local and remote environments. The local environment pertains to individual machines, such as the one I am currently using to record this video, while remote environments encompass various servers. These servers typically include a development server for testing, an integration environment for integration testing, a testing QA environment for quality assurance, a staging environment mirroring production, and finally, the production environment itself.
However, complications arise when considering the development environment. Traditionally, development environments were servers. Still, with the introduction of Rails, a new convention emerged, wherein the development environment also referred to the local machine of the developer. This dual interpretation of the development environment has led to confusion and inconsistencies within development practices.
Furthermore, the proliferation of environment-specific code, particularly within open-source modules, exacerbates this issue. Relying on Node.env to trigger specific behaviors can lead to a fragmented and unreliable codebase, increasing the likelihood of errors and inconsistencies across different environments. Therefore, it is imperative to establish standardized practices for managing environment variables and ensure consistency across development, staging, and production environments to mitigate potential risks and enhance software reliability.
In practice, when deploying, it's customary to set Node.env to "production" universally. This ensures that the code operates in a production environment contextually. However, from a deployment perspective, the value assigned to Node.env can vary widely, such as "foobar," "pippo," "pluto," or "paperino" (as it's referred to in Italy). Essentially, it can be any arbitrary value like "foobar," "baz," or other identifiers like "development," "production," "staging," "UAT," "UAT2," and so forth. This variation in naming conventions can be likened to the diversity in the names of dishes, where preferences may vary, but it doesn't affect the essence of the code.
Regarding its inception, it's unclear why the switch from Connect.env to Node.env occurred. Speculatively, it might have aimed for greater generality, but regardless of the intent, the widespread adoption of Node.env has led to unforeseen consequences. Failure to set Node.env consistently to anything other than "production" can result in unexpected behaviors within the codebase. Both Express and Connect default to a development mode, compounding the complexity.
Considering frontend development, bundlers like Webpack often rely on process.env.node.env to determine the contents of the bundles. Thus, altering Node.env to customize behaviors or domain URLs can inadvertently affect the bundled application content. Therefore, it's strongly advised against using Node.env for such purposes. Instead, setting it to "production" and leaving it unchanged is the recommended practice to ensure consistency and stability across environments.
Examining the usage of Node.env across various libraries reveals its prevalence, especially in popular frameworks like ADONIS, NestJS, Express, and others. Notably, the "config" package stands out as a source of potential trouble due to its method of selecting configuration files based on the nodeM variable, which can cause unintended side effects. It's advisable to avoid such practices and instead adhere to standardized approaches for configuration management.
Regarding configuration management, adhering to the principles outlined in the 12-factor app methodology is paramount. The 12-factor app methodology provides comprehensive guidelines for developing robust, scalable, and maintainable applications. While the publication date of the 12-factor app methodology isn't explicitly stated, its enduring relevance underscores its importance, making it essential reading for developers seeking to build high-quality applications.
In essence, when analyzing the code explicitly, it underscores the problem succinctly: some applications utilize config file names and groups with environments named after specific deployments. However, this approach lacks scalability and cleanliness. Therefore, it's strongly discouraged. It's recommended to explore the 12-factor app methodology, as it offers an excellent way to specify configurations. This methodology remains relevant and timeless, providing invaluable insights for developers seeking to build robust applications.
The primary takeaway from this discussion is to consistently set node_env to "production" when running on a server. This ensures uniformity and stability across various environments. Despite the prevalence of node_env usage in libraries, attempting to alter the entire npm ecosystem is impractical. Instead, focus on setting node_env to "production" universally and avoid relying on it for environment-specific behaviors.
Moreover, avoid creating code that reads node_env to activate specific behaviors for particular environments. This practice is problematic and can lead to confusion, particularly when staging environments are mistakenly treated as production environments. Instead, consider utilizing a custom environment variable, such as "env_my_awesome_feature," to toggle features on and off systematically.
Transitioning to a demonstration of handling environment variables within a Platformatic application, it's essential to understand Platformatic's purpose. It's a tool designed for swiftly building Node.js backends and APIs, streamlining development processes and eliminating redundant tasks. By adhering to the principles outlined in the 12-factor app methodology, developers can efficiently manage configurations and enhance the reliability of their applications.
Utilizing a .env file, developers can introduce environment variables, such as "plt-greeting," to customize application behavior. These variables can then be passed to plugins using decorators, ensuring a clear separation of concerns and preventing pollution of the application codebase. This approach facilitates easy customization and maintenance of the application.
In conclusion, managing configurations effectively is crucial for building robust and scalable applications. By following best practices, such as those outlined in the 12-factor app methodology, developers can streamline development processes and enhance the reliability of their applications. For further exploration, visit platformatic.dev and discover more about our open-source tool. Thank you for watching. Bye-bye.