<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dotenv</title>
    <description>The latest articles on DEV Community by Dotenv (@dotenv).</description>
    <link>https://dev.to/dotenv</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F910008%2F3433d6df-05a5-4098-8960-04df13c40fbb.jpg</url>
      <title>DEV Community: Dotenv</title>
      <link>https://dev.to/dotenv</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dotenv"/>
    <language>en</language>
    <item>
      <title>From dotenv to dotenvx: Next Generation Config Management</title>
      <dc:creator>Dotenv</dc:creator>
      <pubDate>Tue, 25 Jun 2024 14:52:48 +0000</pubDate>
      <link>https://dev.to/dotenv/from-dotenv-to-dotenvx-next-generation-config-management-2104</link>
      <guid>https://dev.to/dotenv/from-dotenv-to-dotenvx-next-generation-config-management-2104</guid>
      <description>&lt;p&gt;The day after July 4th 🇺🇸, I wrote &lt;a href="https://github.com/motdotla/dotenv/commit/71dabbf27b699fcb7a04714709cecfc6e78892b9" rel="noopener noreferrer"&gt;dotenv's first commit&lt;/a&gt; and released &lt;a href="https://www.npmjs.com/package/dotenv/v/0.0.1" rel="noopener noreferrer"&gt;version 0.0.1 on npm&lt;/a&gt;. It looked like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdotenvx%2Fdotenvx%2Fassets%2F3848%2F632a3bf4-50f4-4614-a0c2-12b2f6e64ccc" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdotenvx%2Fdotenvx%2Fassets%2F3848%2F632a3bf4-50f4-4614-a0c2-12b2f6e64ccc"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the 11 years since, it's become one of the &lt;a href="https://gist.github.com/anvaka/8e8fa57c7ee1350e3491#top-1000-most-depended-upon-packages" rel="noopener noreferrer"&gt;most depended-upon packages&lt;/a&gt; worldwide 🌎 – adjacent ubiquitous software like TypeScript and ESLint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdotenvx%2Fdotenvx%2Fassets%2F3848%2F3b93fa70-8204-4563-b5b5-a3a2dcfb3de3" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdotenvx%2Fdotenvx%2Fassets%2F3848%2F3b93fa70-8204-4563-b5b5-a3a2dcfb3de3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's an example of "big things have small beginnings". The &lt;a href="https://github.com/motdotla/dotenv/commit/71dabbf27b699fcb7a04714709cecfc6e78892b9#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5" rel="noopener noreferrer"&gt;README&lt;/a&gt; was short and the &lt;a href="https://github.com/motdotla/dotenv/commit/71dabbf27b699fcb7a04714709cecfc6e78892b9#diff-7934bf411fea192ad8cd69e0a12911648a2842cb0f2409a8fb67b41b7069d757" rel="noopener noreferrer"&gt;code was humble&lt;/a&gt;, but today it's beloved by millions of developers.&lt;/p&gt;

&lt;p&gt;It's one of the few security tools that improve your security posture with minimal fuss.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a single line of code - &lt;code&gt;require('dotenv').config()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a single file - &lt;code&gt;.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a single gitignore append - &lt;code&gt;echo '.env' &amp;gt; .gitignore&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's aesthetic, it's effective, it's elegant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But it's not without its problems!&lt;/strong&gt; And that's what I want to talk about.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problems with &lt;code&gt;dotenv&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In order of importance, there are three big problems with &lt;code&gt;dotenv&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;leaking your .env file&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;juggling multiple environments&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;inconsistency across platforms&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All three pose risks to security, and the first does SIGNIFICANTLY.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But I think we have a solution to all three today - with &lt;a href="https://gitub.com/dotenvx/dotenvx" rel="noopener noreferrer"&gt;dotenvx&lt;/a&gt;&lt;/strong&gt;. In reverse problem order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/dotenvx/dotenvx?tab=readme-ov-file#run-anywhere" rel="noopener noreferrer"&gt;Run Anywhere&lt;/a&gt; -&amp;gt; &lt;em&gt;inconsistency across platforms&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dotenvx/dotenvx?tab=readme-ov-file#multiple-environments" rel="noopener noreferrer"&gt;Multiple Environments&lt;/a&gt; -&amp;gt; &lt;em&gt;juggling multiple environments&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dotenvx/dotenvx?tab=readme-ov-file#encryption" rel="noopener noreferrer"&gt;Encryption&lt;/a&gt; -&amp;gt; &lt;em&gt;leaking your .env file&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dig into each. I'll do my best to show rather than tell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run Anywhere
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/dotenvx/dotenvx" rel="noopener noreferrer"&gt;dotenvx&lt;/a&gt; works the same across every language, framework, and platform – inject your env at runtime with &lt;code&gt;dotenvx run -- your-cmd&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"HELLO=World"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"console.log('Hello ' + process.env.HELLO)"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; index.js

&lt;span class="nv"&gt;$ &lt;/span&gt;node index.js
Hello undefined &lt;span class="c"&gt;# without dotenvx&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;dotenvx run &lt;span class="nt"&gt;--&lt;/span&gt; node index.js
Hello World &lt;span class="c"&gt;# with dotenvx&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; :-D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/dotenvx/dotenvx/blob/6f5a91370437716c93ead3e4400d1ee46e2b77ef/src/lib/helpers/parseDecryptEvalExpand.js#L6" rel="noopener noreferrer"&gt;.env parsing engine&lt;/a&gt;, &lt;a href="https://github.com/dotenvx/dotenvx?tab=readme-ov-file#run-anywhere" rel="noopener noreferrer"&gt;variable expansion&lt;/a&gt;, &lt;a href="https://github.com/dotenvx/dotenvx?tab=readme-ov-file#run-anywhere" rel="noopener noreferrer"&gt;command substitution&lt;/a&gt;, and more work exactly the same. Install dotenvx via &lt;a href="https://dotenvx.com/docs/install#npm" rel="noopener noreferrer"&gt;npm&lt;/a&gt;, &lt;a href="https://dotenvx.com/docs/install#brew" rel="noopener noreferrer"&gt;brew&lt;/a&gt;, &lt;a href="https://dotenvx.com/docs/install#shell" rel="noopener noreferrer"&gt;curl&lt;/a&gt;, &lt;a href="https://dotenvx.com/docs/install#docker" rel="noopener noreferrer"&gt;docker&lt;/a&gt;, &lt;a href="https://docs/install#windows" rel="noopener noreferrer"&gt;windows&lt;/a&gt;, and &lt;a href="https://dotenvx.com/docs/install" rel="noopener noreferrer"&gt;more&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This solves the problem of &lt;em&gt;inconsistency across platforms&lt;/em&gt;. ✅ You'll get the exact same behavior for your &lt;a href="https://dotenvx.com/docs/guides#python" rel="noopener noreferrer"&gt;python apps&lt;/a&gt; as your &lt;a href="https://dotenvx.com/docs/guides#node-js" rel="noopener noreferrer"&gt;node apps&lt;/a&gt; as your &lt;a href="https://dotenvx.com/docs/guides#go" rel="noopener noreferrer"&gt;rust apps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dotenvx/dotenvx?tab=readme-ov-file#run-anywhere" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdotenvx%2Fdotenvx%2Fassets%2F3848%2F6a43eb52-4b1d-48c2-8c7a-b62cb35b526b"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiple Environments
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;.env.production&lt;/code&gt; file and use &lt;code&gt;-f&lt;/code&gt; to load it. It's straightforward, yet flexible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"HELLO=production"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env.production
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"console.log('Hello ' + process.env.HELLO)"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; index.js

&lt;span class="nv"&gt;$ &lt;/span&gt;dotenvx run &lt;span class="nt"&gt;-f&lt;/span&gt; .env.production &lt;span class="nt"&gt;--&lt;/span&gt; node index.js
&lt;span class="o"&gt;[&lt;/span&gt;dotenvx][info] loading &lt;span class="nb"&gt;env&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; from .env.production
Hello production
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ^^
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While everything in &lt;a href="https://github.com/dotenvx/dotenvx" rel="noopener noreferrer"&gt;dotenvx&lt;/a&gt; is inspired by community suggestions, this multi-environment feature particularly is. There were suggestions many times for something similar before I came to understand its usefulness. I'm convinvced now it cleanly solves the problem of &lt;em&gt;juggling multiple environments&lt;/em&gt; when built into the command line. ✅&lt;/p&gt;

&lt;p&gt;You can even compose multiple environments together with multiple &lt;code&gt;-f&lt;/code&gt; flags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"HELLO=local"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env.local
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"HELLO=World"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"console.log('Hello ' + process.env.HELLO)"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; index.js

&lt;span class="nv"&gt;$ &lt;/span&gt;dotenvx run &lt;span class="nt"&gt;-f&lt;/span&gt; .env.local &lt;span class="nt"&gt;-f&lt;/span&gt; .env &lt;span class="nt"&gt;--&lt;/span&gt; node index.js
&lt;span class="o"&gt;[&lt;/span&gt;dotenvx] injecting &lt;span class="nb"&gt;env&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; from .env.local, .env
Hello &lt;span class="nb"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/dotenvx/dotenvx?tab=readme-ov-file#multiple-environments" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdotenvx%2Fdotenvx%2Fassets%2F3848%2F8983a359-32f9-459a-861c-66bfdf4e87a1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Handy! But it's the next feature, &lt;strong&gt;encryption&lt;/strong&gt;, that is the real game changer (and I think merits dotenvx as the &lt;em&gt;next generation of configuration management&lt;/em&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Encryption
&lt;/h2&gt;

&lt;p&gt;Add encryption to your .env files with a single command. Run &lt;code&gt;dotenvx encrypt&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dotenvx encrypt
✔ encrypted &lt;span class="o"&gt;(&lt;/span&gt;.env&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;#/-------------------[DOTENV_PUBLIC_KEY]--------------------/
#/            public-key encryption for .env files          /
#/       [how it works](https://dotenvx.com/encryption)     /
#/----------------------------------------------------------/
&lt;/span&gt;&lt;span class="py"&gt;DOTENV_PUBLIC_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"03f8b376234c4f2f0445f392a12e80f3a84b4b0d1e0c3df85c494e45812653c22a"&lt;/span&gt;

&lt;span class="c"&gt;# Database configuration
&lt;/span&gt;&lt;span class="py"&gt;DB_HOST&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"encrypted:BNr24F4vW9CQ37LOXeRgOL6QlwtJfAoAVXtSdSfpicPDHtqo/Q2HekeCjAWrhxHy+VHAB3QTg4fk9VdIoncLIlu1NssFO6XQXN5fnIjXRmp5pAuw7xwqVXe/1lVukATjG0kXR4SHe45s4Tb6fEjs"&lt;/span&gt;
&lt;span class="py"&gt;DB_PORT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"encrypted:BOCHQLIOzrq42WE5zf431xIlLk4iRDn1/hjYBg5kkYLQnL9wV2zEsSyHKBfH3mQdv8w4+EhXiF4unXZi1nYqdjVp4/BbAr777ORjMzyE+3QN1ik1F2+W5DZHBF9Uwj69F4D7f8A="&lt;/span&gt;
&lt;span class="py"&gt;DB_USER&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"encrypted:BP6jIRlnYo5LM6/n8GnOAeg4RJlPD6ZN/HkdMdWfgfbQBuZlo44idYzKApdy0znU3TSoF5rcppXIMkxFFuB6pS0U4HMG/jl46lPCswl3vLTQ7Gx5EMT6YwE6pfA88AM77/ebQZ6y0L5t"&lt;/span&gt;
&lt;span class="py"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"encrypted:BMycwcycXFFJQHjbt1i1IBS7C31Fo73wFzPolFWwkla09SWGy3QU1rBvK0YwdQmbuJuztp9JhcNLuc0wUdlLZVHC4/E6q/K7oPULNPxC5K1LwW4YuX80Ngl6Oy13Twero864f2DXXTNb"&lt;/span&gt;
&lt;span class="py"&gt;DB_NAME&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"encrypted:BGtVHZBbvHmX6J+J+xm+73SnUFpqd2AWOL6/mHe1SCqPgMAXqk8dbLgqmHiZSbw4D6VquaYtF9safGyucClAvGGMzgD7gdnXGB1YGGaPN7nTpJ4vE1nx8hi1bNtNCr5gEm7z+pdLq1IsH4vPSH4O7XBx"&lt;/span&gt;

&lt;span class="c"&gt;# API Keys
&lt;/span&gt;&lt;span class="py"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"encrypted:BD9paBaun2284WcqdFQZUlDKapPiuE/ruoLY7rINtQPXKWcfqI08vFAlCCmwBoJIvd2Nv3ACiSCA672wsKeJlFJTcRB6IRRJ+fPBuz2kvYlOiec7EzHTT8EVzSDydFun5R5ODfmN"&lt;/span&gt;
&lt;span class="py"&gt;STRIPE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"encrypted:BM6udWmFsPaBzlND0dFBv7R55JiaA+cZnbun8DaVNrEvO+8/k+lsXbZQ0bCPks8kUsdD2qrSp/tii0P8gVJ/gp+pdDuhdcJj91hxJ7nzSFf6h0ofRb38/2WHFhxg77XExxzui1s3w42Z"&lt;/span&gt;

&lt;span class="c"&gt;# Logging
&lt;/span&gt;&lt;span class="py"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"encrypted:BKmgv5E7/l1FnSaGWYWBPxxagdgN+KSEaB+va3PePjwEp7CqW6PlysrweZq49YTB5Fbc3UN/akLVn1RZ2AO4PyTVqgYYGBwerjpJiou9R2KluNV3T4j0bhsAkBochg3YpHcw3RX/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;DOTENV_PUBLIC_KEY&lt;/code&gt; (encryption key) and a &lt;code&gt;DOTENV_PRIVATE_KEY&lt;/code&gt; (decryption key) are generated using the same public-key cryptography as &lt;a href="https://en.bitcoin.it/wiki/Secp256k1" rel="noopener noreferrer"&gt;Bitcoin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, even if you leak your .env file, it's ok. An attacker needs the &lt;code&gt;DOTENV_PRIVATE_KEY&lt;/code&gt; to make sense of things. This effectively solves the problem of &lt;em&gt;leaking your .env file&lt;/em&gt; ✅.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dotenvx/dotenvx?tab=readme-ov-file#encryption" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fdotenvx%2Fdotenvx%2Fassets%2F3848%2F42aef834-50d9-4187-93e4-b5230ae1253a"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus:&lt;/strong&gt; This approach additionally makes it possible for contributors to add config while simultaneously being unable to decrypt config. I anticipate this will be useful for open source projects where you want to allow for contribution of secrets without decryption of prior secrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.0.0 Release
&lt;/h2&gt;

&lt;p&gt;With that, we're pleased to announce the release of &lt;a href="https://www.npmjs.com/package/@dotenvx/dotenvx" rel="noopener noreferrer"&gt;dotenvx version 1.0.0&lt;/a&gt; 🎉.&lt;/p&gt;

&lt;p&gt;It is the &lt;em&gt;next generation of configuration management&lt;/em&gt;, and I'm looking forward to what you do with it. The next decade (like the last) is bright for dotenv! 🌟&lt;/p&gt;




&lt;p&gt;If you enjoyed this post, please &lt;a href="https://github.com/dotenvx/dotenvx" rel="noopener noreferrer"&gt;share dotenvx with friends&lt;/a&gt; or &lt;a href="https://github.com/dotenvx/dotenvx" rel="noopener noreferrer"&gt;star it on GitHub&lt;/a&gt; to help spread the word.&lt;/p&gt;

</description>
      <category>dotenv</category>
      <category>node</category>
    </item>
    <item>
      <title>Community Spotlight: David Cochrum</title>
      <dc:creator>Dotenv</dc:creator>
      <pubDate>Mon, 13 Nov 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/dotenv/community-spotlight-david-cochrum-55an</link>
      <guid>https://dev.to/dotenv/community-spotlight-david-cochrum-55an</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rkE1K-Yq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/community-spotlight-david-cochrum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rkE1K-Yq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/community-spotlight-david-cochrum.png" alt="" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Meet &lt;a href="https://chrum.me/"&gt;David Cochrum&lt;/a&gt;, the creator of &lt;a href="https://github.com/davidcochrum/dotenv-vault-laravel"&gt;dotenv-vault-laravel&lt;/a&gt;. He’s a full stack software engineer that specializes in PHP and JavaScript.&lt;/p&gt;

&lt;p&gt;In this spotlight post, I ask him some questions about Laravel, as well as the &lt;code&gt;.env.vault&lt;/code&gt; file format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 1: Laravel Ecosystem
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Having worked with Laravel for some time, what significant changes have you observed in the framework and its ecosystem? How have these changes influenced your development approach?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Over the years of working with Laravel, I have seen the level of convenience grow while the learning curve shrunk. Obviously, Laravel is quite opinionated in its approach, but those opinions cover the vast majority of use cases and generally make the framework a breeze to work with.&lt;/p&gt;

&lt;p&gt;Take create, read, update, and delete (CRUD) operations, for example. So much of web apps are CRUD operations against resource models. Laravel added a great convenience when it &lt;a href="https://laravel.com/docs/5.5/releases"&gt;introduced resource controllers&lt;/a&gt; and &lt;a href="https://laravel.com/docs/5.4/releases"&gt;route model binding&lt;/a&gt; to go with it. So long as you’re following the Laravel conventions, much of the boilerplate work is handled for you. That in turn empowers developers to crank out more functionality without dying of boredom along the way.&lt;/p&gt;

&lt;p&gt;I believe the popularity of Laravel has grown largely due to of these opinionated conveniences. As such, there’s a package to add on just about any common functionality these days directly through Packagist and GitHub. Third-party packages also benefit from auto discovery to the point where most can be added just by including the Composer dependency. The integration and configuration of these auto-discovered packages within your app is effortless and often requires no further modification than the installation.&lt;/p&gt;

&lt;p&gt;Now, the Computer Science purists will also tell you that some of Laravel’s conventions and conveniences come at the cost of breaking certain programming paradigms and principles. While this is undeniably true, in my humble opinion, Laravel does a pretty decent job of balancing principles with practicality. Sure, Facades are an example of an anti-pattern, but I think, when used responsibly, the benefits can outweigh the penalty of broken rules.&lt;/p&gt;

&lt;p&gt;Early on when I first started real app development, the seniors above me decided to base our re-build on Symfony. While this allowed for some low-level convenience, the decision was also made that the Symfony validation package wasn’t good enough for our purposes and instead, each CRUD module would require complex validator classes for each of the forms within. I believe we wasted quite a bit of developer time/resources in re-inventing a pretty decent wheel. Reflecting on that time now, I believe that was a huge mistake. Yes, it was the more principled approach, but I don’t think we gained much, if anything, by writing our own validation instead of leveraging the widely used package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 2: Laravel Benefits
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Laravel is known for its elegant syntax and robust features. Can you share an example from your experience where Laravel uniquely benefited a project you worked on, perhaps in ways other PHP frameworks might not have?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my opinion, Laravel’s most valuable feature is how it allows you to go from nothing to a minimum viable product (MVP) faster than any other framework. Because of its popularity, so many community packages are available to be quickly integrated into your project as well. Say you need to add OAuth to your project, for example. With other frameworks or languages, that typically requires a significant amount of work. Whereas with Laravel, the OAuth package offered, &lt;a href="https://laravel.com/docs/10.x/fortify"&gt;Fortify&lt;/a&gt;, does the overwhelming majority of the work for you and requires minimal effort to integrate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 3: Your Experience with Laravel
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;What drew you to specialize in Laravel, and how has it shaped your journey as a developer? Are there any projects or achievements within the Laravel community that you’re particularly proud of?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I wouldn’t say I necessarily specialize in Laravel, but it is definitely my framework of choice when I’m offered a choice. I’ve worked on projects using Symfony, CodeIgniter v3, Zend v1, and even a homegrown framework that predates all of the others.&lt;/p&gt;

&lt;p&gt;Many moons ago I was tasked with extending and maintaining APIs for various mobile apps which were all bundled into a single WordPress XMLRPC plugin. I was given more freedom on one project and I presented the case that I should be given the time to learn and build this next API using a concept I had just heard of: Object Oriented Programming (OOP). I was successful in convincing the stakeholders that allowing me the time to learn and build in this way would be worthwhile. I tried out numerous frameworks, but with the help of &lt;a href="https://laracasts.com/"&gt;Jeffrey Way’s Laracasts&lt;/a&gt;, Laravel just seemed to come so naturally and truly helped me learn and adopt programming principles that I hadn’t known before.&lt;/p&gt;

&lt;p&gt;Speaking of Laracasts, I would consider that project and community one of the best things to come from Laravel. I’m sure many other developers like myself got their start from working through those videos and tutorials. I certainly wouldn’t be where I am today without Laracasts. Nor would I be as efficient as I am within my IDE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 4: Laraval with .env.vault
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;What drew you to the .env.vault mechanism? How do you think it will affect the Laravel ecosystem? Is it useful to it? Laravel has its own encryption mechanism for .env files, how is .env.vault different and or more useful in your mind?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’m currently working on a Zend Framework v1 monolith project that my team and I are attempting to modernize. These apps use Zend’s ini files for configuration which also can be overridden via .env values. I’m working on protecting these secrets and making them more portable while simultaneously starting the process of migrating the apps from Zend to Laravel. During my search for solutions, I came across &lt;a href="https://www.dotenv.org/"&gt;dotenv.org&lt;/a&gt; and its vault for secure secret storage that seemed to fit my needs. I did, however, see an opportunity to author &lt;a href="https://github.com/davidcochrum/dotenv-vault-laravel"&gt;my first Laravel package&lt;/a&gt; which simply wrapped the &lt;a href="https://github.com/dotenv-org/phpdotenv-vault"&gt;PHP Dotenv library&lt;/a&gt; for dead-simple integration with the framework.&lt;/p&gt;

&lt;p&gt;I think the vault mechanism can be useful for those who are looking for a storage solution for their secrets which may not be available or is costly with their hosting provider. Additionally, the remote sync feature offered on &lt;a href="https://www.dotenv.org"&gt;dotenv.org&lt;/a&gt; with the potential for granular access control across user accounts adds a great value that is missing from Laravel’s encryption mechanism.&lt;/p&gt;




&lt;p&gt;Thank you David for the thoughts and for your &lt;a href="https://github.com/davidcochrum/dotenv-vault-laravel"&gt;dotenv-vault-laravel&lt;/a&gt; contribution to the Laravel community.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ebUBG6Ze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/community-spotlight-david-cochrum-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ebUBG6Ze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/community-spotlight-david-cochrum-1.png" alt="" width="510" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iFyFCD2N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/community-spotlight-david-cochrum-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iFyFCD2N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/community-spotlight-david-cochrum-2.png" alt="" width="510" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotenv</category>
      <category>laravel</category>
      <category>dotenvvault</category>
    </item>
    <item>
      <title>PHP dotenv is inconsistent across development and production</title>
      <dc:creator>Dotenv</dc:creator>
      <pubDate>Tue, 07 Nov 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/dotenv/php-dotenv-is-inconsistent-across-development-and-production-40gf</link>
      <guid>https://dev.to/dotenv/php-dotenv-is-inconsistent-across-development-and-production-40gf</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1grLyc5o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/phpdotenv-is-inconsistent.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1grLyc5o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/phpdotenv-is-inconsistent.png" alt="" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently added &lt;a href="https://github.com/dotenv-org/phpdotenv-vault"&gt;&lt;code&gt;.env.vault&lt;/code&gt; support for PHP&lt;/a&gt;, and I came across serious inconsistencies across development and production using &lt;a href="https://github.com/vlucas/phpdotenv"&gt;phpdotenv&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Values can come up blank (yikes!) and &lt;code&gt;load&lt;/code&gt; works differently than the &lt;a href="https://github.com/theskumar/python-dotenv"&gt;other&lt;/a&gt; &lt;a href="https://github.com/bkeepers/dotenv"&gt;major&lt;/a&gt; &lt;a href="https://github.com/motdotla/dotenv"&gt;dotenv&lt;/a&gt; libraries.&lt;/p&gt;

&lt;p&gt;Luckily, the fix is straightforward.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;$_SERVER&lt;/code&gt; - don’t use &lt;code&gt;$_ENV&lt;/code&gt; or &lt;code&gt;getenv&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;safeLoad()&lt;/code&gt; - don’t use &lt;code&gt;.load()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive in.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Also, let me say that I know how difficult it is to maintain a widely-embedded library like &lt;a href="https://github.com/vlucas/phpdotenv"&gt;phpdotenv&lt;/a&gt;. There are good historical reasons a library might have inconsistencies. Sometimes changing the inconsistencies leads to worse cascading effects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Install &lt;a href="https://github.com/vlucas/phpdotenv"&gt;phpdotenv&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require vlucas/phpdotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HELLO="File"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then load your &lt;code&gt;.env&lt;/code&gt; file in a way that will output &lt;code&gt;Hello File&lt;/code&gt; using each available accessor.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;$_ENV&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$_SERVER&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getenv&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
// example1.php
require 'vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable( __DIR__ );
$dotenv-&amp;gt;load();

$env_hello = $_ENV['HELLO'];
$server_hello = $_SERVER['HELLO'];
$getenv_hello = getenv('HELLO');

echo "ENV: Hello {$env_hello}";
echo "\n";
echo "SERVER: Hello {$server_hello}";
echo "\n";
echo "getenv: Hello {$getenv_hello}";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, let’s run some scenarios demonstrating the inconsistencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario 1 - &lt;code&gt;getenv&lt;/code&gt; missing value
&lt;/h3&gt;

&lt;p&gt;In the first scenario, the &lt;code&gt;getenv&lt;/code&gt; value comes back blank.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
// example1.php
require 'vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable( __DIR__ );
$dotenv-&amp;gt;load();

$env_hello = $_ENV['HELLO'];
$server_hello = $_SERVER['HELLO'];
$getenv_hello = getenv('HELLO');

echo "ENV: Hello {$env_hello}";
echo "\n";
echo "SERVER: Hello {$server_hello}";
echo "\n";
echo "getenv: Hello {$getenv_hello}";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ php example1.php
ENV: Hello File
SERVER: Hello File
getenv: Hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;getenv&lt;/code&gt; returns &lt;code&gt;Hello [blank]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 2 - &lt;code&gt;createUnsafeImmutable&lt;/code&gt; not thread-safe
&lt;/h3&gt;

&lt;p&gt;In the second scenario, we remove thread-safety.&lt;/p&gt;

&lt;p&gt;Change &lt;code&gt;createImmutable&lt;/code&gt; to &lt;code&gt;createUnsafeImmutable&lt;/code&gt; in order to populate data to &lt;code&gt;getenv&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
// example2
require 'vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createUnsafeImmutable( __DIR__ );
$dotenv-&amp;gt;load();

$env_hello = $_ENV['HELLO'];
$server_hello = $_SERVER['HELLO'];
$getenv_hello = getenv('HELLO');

echo "ENV: Hello {$env_hello}";
echo "\n";
echo "SERVER: Hello {$server_hello}";
echo "\n";
echo "getenv: Hello {$getenv_hello}";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ php example2.php
ENV: Hello File
SERVER: Hello File
getenv: Hello File
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works. &lt;code&gt;getenv&lt;/code&gt; now correctly returns &lt;code&gt;Hello File&lt;/code&gt;, but it is &lt;a href="https://github.com/vlucas/phpdotenv#putenv-and-getenv"&gt;not thread safe&lt;/a&gt; - super dangerous for any production application!&lt;/p&gt;

&lt;p&gt;So, let’s switch it back to &lt;code&gt;createImmutable&lt;/code&gt; and try something else.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 3 - &lt;code&gt;$_ENV&lt;/code&gt; missing value
&lt;/h3&gt;

&lt;p&gt;In the third scenario, &lt;code&gt;$_ENV&lt;/code&gt; comes back blank.&lt;/p&gt;

&lt;p&gt;Mimic the behavior of an already set environment variable on the server by pre-setting &lt;code&gt;HELLO=Server&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
// example1.php
require 'vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable( __DIR__ );
$dotenv-&amp;gt;load();

$env_hello = $_ENV['HELLO'];
$server_hello = $_SERVER['HELLO'];
$getenv_hello = getenv('HELLO');

echo "ENV: Hello {$env_hello}";
echo "\n";
echo "SERVER: Hello {$server_hello}";
echo "\n";
echo "getenv: Hello {$getenv_hello}";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ HELLO="Server" php example1.php
PHP Warning: Undefined array key "HELLO" in /Users/scottmotte/Code/dotenv-org/examples/dotenv-blog/2023-11-07/example1.php on line 8
Warning: Undefined array key "HELLO" in /Users/scottmotte/Code/dotenv-org/examples/dotenv-blog/2023-11-07/example1.php on line 8

ENV: Hello
SERVER: Hello Server
getenv: Hello Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$_ENV&lt;/code&gt; is blank (and we get a warning)! This is inconsistent behavior between development and production.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;$_SERVER&lt;/code&gt; is consistent in all three scenarios. Use that going forward. Easy enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;load()&lt;/code&gt; vs &lt;code&gt;safeLoad()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In the other 3 major dotenv libraries (&lt;a href="https://github.com/motdotla/dotenv"&gt;node&lt;/a&gt;, &lt;a href="https://github.com/bkeepers/dotenv"&gt;ruby&lt;/a&gt;, &lt;a href="https://github.com/theskumar/python-dotenv"&gt;python&lt;/a&gt;), the &lt;code&gt;load&lt;/code&gt; method quietly does nothing when a &lt;code&gt;.env&lt;/code&gt; file is not present.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is for good reason. Your &lt;code&gt;.env&lt;/code&gt; file is not committed to code. So when you deploy your code to production (or ci) there is no &lt;code&gt;.env&lt;/code&gt; file present. The expecation is the server already has your environment variables in memory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s see what &lt;a href="https://github.com/vlucas/phpdotenv"&gt;phpdotenv&lt;/a&gt; does in this scenario.&lt;/p&gt;

&lt;p&gt;Remove your &lt;code&gt;.env&lt;/code&gt; file and run the script again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rm .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ php example1.php
PHP Fatal error: Uncaught Dotenv\Exception\InvalidPathException: Unable to read any of the environment file(s) at [../.env]. in /../vendor/vlucas/phpdotenv/src/Store/FileStore.php:68
Stack trace:
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It issues a stacktrace error, killing your app!&lt;/p&gt;

&lt;p&gt;This really surprised me because this is a really dangerous default. It encourages the developer to commit their &lt;code&gt;.env&lt;/code&gt; file to code to fix the problem.&lt;/p&gt;

&lt;p&gt;Luckily, the fix is easy again. Use &lt;code&gt;safeLoad&lt;/code&gt; instead of &lt;code&gt;load&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But in my experience, a developer new to &lt;code&gt;.env&lt;/code&gt; files won’t have the experience to correctly reach for &lt;code&gt;safeLoad&lt;/code&gt; here. They are too likely to commit their &lt;code&gt;.env&lt;/code&gt; file to code and move on with their day. I’ll admit I don’t have the historical context for this decision here, but currently I think this naming pattern should be reversed. &lt;code&gt;load&lt;/code&gt; should be become something like &lt;code&gt;loadAndHaltIfMissingEnv&lt;/code&gt;, and &lt;code&gt;safeLoad&lt;/code&gt; should become &lt;code&gt;load&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Anyways, let’s see the fix.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
// example3
require 'vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable( __DIR__ );
$dotenv-&amp;gt;safeLoad(); // &amp;lt;--- use safeLoad

$env_hello = $_ENV['HELLO'];
$server_hello = $_SERVER['HELLO'];
$getenv_hello = getenv('HELLO');

echo "ENV: Hello {$env_hello}";
echo "\n";
echo "SERVER: Hello {$server_hello}";
echo "\n";
echo "getenv: Hello {$getenv_hello}";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ php example3.php
ENV: Hello
SERVER: Hello
getenv: Hello

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All blank values and no stacktrace, as it should be.&lt;/p&gt;

&lt;p&gt;Let’s simulate production again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ HELLO="Server" php example3.php
ENV: Hello
SERVER: Hello Server
getenv: Hello Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$_SERVER&lt;/code&gt; correctly returns &lt;code&gt;Hello Server&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Phew 💛🌴, I’m feeling better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, use &lt;code&gt;$_SERVER&lt;/code&gt;, and use &lt;code&gt;safeLoad&lt;/code&gt; instead of &lt;code&gt;load&lt;/code&gt;. Do the same when using &lt;a href="https://github.com/dotenv-org/phpdotenv-vault"&gt;phpdotenv-vault&lt;/a&gt; with encrypted &lt;code&gt;.env.vault&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Happy PHPing!&lt;/p&gt;

</description>
      <category>blog</category>
    </item>
    <item>
      <title>Node.js 20.6.0 includes built-in support for .env files</title>
      <dc:creator>Dotenv</dc:creator>
      <pubDate>Sat, 28 Oct 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/dotenv/nodejs-2060-includes-built-in-support-for-env-files-50mh</link>
      <guid>https://dev.to/dotenv/nodejs-2060-includes-built-in-support-for-env-files-50mh</guid>
      <description>&lt;p&gt;Node v20.6.0+ adds native support for loading &lt;code&gt;.env&lt;/code&gt; files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --env-file=.env index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wow, cool!&lt;/p&gt;

&lt;p&gt;Is &lt;a href="https://github.com/motdotla/dotenv"&gt;dotenv&lt;/a&gt; &lt;a href="https://francoisbest.com/posts/2023/dotenv-is-dead?ref=dailydev"&gt;dead&lt;/a&gt;? &lt;a href="https://medium.com/@tony.infisical/stop-using-dotenv-in-node-js-v20-6-0-8febf98f6314"&gt;Stop using it&lt;/a&gt;? Not so fast. &lt;strong&gt;Don’t drop dotenv&lt;/strong&gt; just yet. There are some caveats you should know first.&lt;/p&gt;

&lt;p&gt;First, let me say, it is great to see the NodeJS team adopt first-class &lt;code&gt;.env&lt;/code&gt; support for developers. As &lt;a href="https://github.com/motdotla/dotenv/graphs/contributors"&gt;one of the pioneers of dotenv&lt;/a&gt;, it’s an honor. &lt;strong&gt;dotenv&lt;/strong&gt; is depended on by more than &lt;a href="https://github.com/motdotla/dotenv/network/dependents"&gt;14 Million&lt;/a&gt; open source repos on GitHub alone and downloaded more than &lt;a href="https://www.npmjs.com/package/dotenv"&gt;35 Million&lt;/a&gt; times per week. &lt;a href="https://github.com/motdotla/dotenv"&gt;dotenv&lt;/a&gt; has proven itself as a trusty friend to millions of developers worldwide.&lt;/p&gt;

&lt;p&gt;Anyways, let’s see how this built-in support works (or skip to the caveats section).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Find a complete &lt;a href="https://github.com/dotenv-org/examples/tree/master/dotenv-blog/2023-10-28"&gt;code example on GitHub&lt;/a&gt; for this blog post.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Install Node v20.6.0 or greater using &lt;a href="https://github.com/nvm-sh/nvm"&gt;nvm&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm install 20.6.0
nvm use 20.6.0
node -v
v20.6.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create your &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HELLO="World"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create your node script to make use of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// index.js
console.log(`Hello ${process.env.HELLO}`)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with the &lt;code&gt;--env-file&lt;/code&gt; flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --env-file=.env index.js
Hello World
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it!&lt;/p&gt;

&lt;p&gt;Want to run it in production? Just point it to a &lt;code&gt;.env.production&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env.production
HELLO="production"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --env-file=.env.production index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;The biggest &lt;em&gt;current&lt;/em&gt; caveat is that this is still an experimental feature. That means it will ship with &lt;a href="https://github.com/nodejs/node/pull/49424#issue-1876566254"&gt;bugs&lt;/a&gt; and with &lt;a href="https://github.com/nodejs/node/issues/49148"&gt;missing feature support&lt;/a&gt;. The &lt;a href="https://news.ycombinator.com/item?id=37174916"&gt;top hn comment&lt;/a&gt; sums it up well - albeit a bit grumpily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BBM8tnRo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/hacker-news-node-dotenv-support.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BBM8tnRo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/hacker-news-node-dotenv-support.png" alt="" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also want stress the word &lt;em&gt;current&lt;/em&gt; because this is all still under active development. These things take time. By the time you read this, some of these caveats might no longer be around.&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing multiline support
&lt;/h3&gt;

&lt;p&gt;The current implementation does not support multiline environment variables. If you attempt to include a multiline environment variable it will be &lt;code&gt;undefined&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env.multiline
HELLO="This
is
a
multiline"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// index.js
console.log(`Hello ${process.env.HELLO}`)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --env-file=.env.multiline index.js
Hello undefined
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: multiline support is being actively discussed and will probably get added in the near future.&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing override option
&lt;/h3&gt;

&lt;p&gt;You cannot override your system’s environment variables with your &lt;code&gt;.env&lt;/code&gt; file. There is no option.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env
HELLO="World"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// index.js
console.log(`Hello ${process.env.HELLO}`)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export HELLO="System"
node --env-file=.env index.js
Hello System
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints &lt;code&gt;Hello System&lt;/code&gt; rather then &lt;code&gt;Hello World&lt;/code&gt;. There is no option to overwrite system variables.&lt;/p&gt;

&lt;p&gt;If you need to do this then continue using dotenv with &lt;a href="https://github.com/motdotla/dotenv#override"&gt;its override option&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing variable expansion
&lt;/h3&gt;

&lt;p&gt;It’s important to note that variable expansion support has always existed in a separate library &lt;a href="https://github.com/motdotla/dotenv-expand"&gt;dotenv-expand&lt;/a&gt;. But it is so &lt;a href="https://www.npmjs.com/package/dotenv-expand"&gt;widely used with 13 million downloads&lt;/a&gt; that it defacto considered part of dotenv.&lt;/p&gt;

&lt;p&gt;As of this writing, Node does not support variable expansion. Instead, it will output the variable as a string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env
PASSWORD="password123"
SECRET=$PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// index.js
console.log(`The secret is ${process.env.SECRET}`)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --env-file=.env index.js
The secret is $PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if you need variable expansion, you should continue using &lt;a href="https://github.com/motdotla/dotenv"&gt;dotenv&lt;/a&gt; and &lt;a href="https://github.com/motdotla/dotenv-expand"&gt;dotenv-expand&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing &lt;code&gt;.env.vault&lt;/code&gt; support
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;.env.vault&lt;/code&gt; file is the spiritual successor to the &lt;code&gt;.env&lt;/code&gt; file. They have multiple security advantages which you can &lt;a href="https://www.dotenv.org/blog/2023/10/24/what-is-env-vault-file.html"&gt;read about here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;They are &lt;a href="https://github.com/motdotla/dotenv/pull/730"&gt;quite new&lt;/a&gt; but also quite useful for production and ci. They are gaining adoption across multiple languages like &lt;a href="https://github.com/dotenv-org/python-dotenv-vault"&gt;python&lt;/a&gt; and &lt;a href="https://docs.rs/dotenv-vault/latest/dotenv_vault/"&gt;rust&lt;/a&gt;. &lt;a href="https://github.com/motdotla/dotenv"&gt;dotenv&lt;/a&gt; supports them but Node’s implementation of &lt;code&gt;.env&lt;/code&gt; files does not at this time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#/-------------------.env.vault---------------------/
#/ cloud-agnostic vaulting standard /
#/ [how it works](https://dotenv.org/env-vault) /
#/--------------------------------------------------/
# development
DOTENV_VAULT_DEVELOPMENT="AtEC33ZfFJQMSE6C+EBX8nzTyQzfC+xhsIfGjyWr47jiHsUi07PHzX2/RmCB0PIi"
# production
DOTENV_VAULT_PRODUCTION="t9van8HefnTIHVlK3vQ6WYLtWEOvPunEnOphV3Hw3aBTBDuwLq22yU0Tdl5fAnk="
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, built-in support for &lt;code&gt;.env&lt;/code&gt; files (even if currently experimental) is a huge and welcome step forward for Node. We should particularly thank Yagiz Nizipli for making this happen. &lt;a href="https://github.com/sponsors/anonrig"&gt;Go sponsor him on GitHub&lt;/a&gt;. He is doing incredible work for Node.&lt;/p&gt;

&lt;p&gt;That said, there are some caveats, and I would recommend against npm uninstall-ing dotenv for your production apps at this time. Wait until it is non-experimental and has added support for the missing features above.&lt;/p&gt;




&lt;h3&gt;
  
  
  Using &lt;code&gt;.env&lt;/code&gt; files?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/dotenv-org/dotenv-vault"&gt;dotenv-vault&lt;/a&gt; is a secrets manager for securely managing them. &lt;a href="https://dotenv.org"&gt;Create your Dotenv Account&lt;/a&gt; and try it today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZwfxvqEE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/dotenv-vault-screenshot2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZwfxvqEE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/dotenv-vault-screenshot2.png" alt="" width="800" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dotenv.org/signup"&gt;https://dotenv.org/signup&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotenv</category>
      <category>secrets</category>
      <category>devops</category>
    </item>
    <item>
      <title>What is a .env.vault file</title>
      <dc:creator>Dotenv</dc:creator>
      <pubDate>Tue, 24 Oct 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/dotenv/what-is-a-envvault-file-3ofj</link>
      <guid>https://dev.to/dotenv/what-is-a-envvault-file-3ofj</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0BjQA9tj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/what-is-env-file-example.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0BjQA9tj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/what-is-env-file-example.png" alt="" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s an encrypted copy of your &lt;code&gt;.env&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;It is easiest to understand if you generate one. So let’s do that. Then I’ll show you how to use it in production. Lastly, we’ll talk about its security advantages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating
&lt;/h2&gt;

&lt;p&gt;We’re going to use the command &lt;code&gt;npx dotenv-vault local build&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Enter a project where you already have &lt;code&gt;.env.*&lt;/code&gt; file(s) and have installed &lt;a href="https://github.com/motdotla/dotenv"&gt;dotenv&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, I have a project with 3 files in it. See &lt;a href="https://github.com/dotenv-org/examples/tree/master/dotenv-blog/what-is-env-vault-file"&gt;example code&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;index.js&lt;/li&gt;
&lt;li&gt;.env&lt;/li&gt;
&lt;li&gt;.env.production
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// index.js
require('dotenv').config()
console.log(`Hello ${process.env.HELLO}`)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env
HELLO="development"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env.production
HELLO="production"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I run &lt;code&gt;node index.js&lt;/code&gt; I get the expected output &lt;code&gt;Hello development&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ node index.js
Hello development
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s build the &lt;code&gt;.env.vault&lt;/code&gt; file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Generate .env.vault
&lt;/h4&gt;

&lt;p&gt;Run the &lt;strong&gt;local build&lt;/strong&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx dotenv-vault local build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see a &lt;code&gt;.env.vault&lt;/code&gt; file that looks something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#/-------------------.env.vault---------------------/
#/ cloud-agnostic vaulting standard /
#/ [how it works](https://dotenv.org/env-vault) /
#/--------------------------------------------------/
# development
DOTENV_VAULT_DEVELOPMENT="AtEC33ZfFJQMSE6C+EBX8nzTyQzfC+xhsIfGjyWr47jiHsUi07PHzX2/RmCB0PIi"
# production
DOTENV_VAULT_PRODUCTION="t9van8HefnTIHVlK3vQ6WYLtWEOvPunEnOphV3Hw3aBTBDuwLq22yU0Tdl5fAnk="
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It contains two keys.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DOTENV_VAULT_DEVELOPMENT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DOTENV_VAULT_PRODUCTION&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These contain encrypted copies of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your &lt;code&gt;.env&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;your &lt;code&gt;.env.production&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;code&gt;.env.keys&lt;/code&gt; file was also generated. These keys decrypt the contents of &lt;code&gt;DOTENV_VAULT_${ENVIRONMENT}&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx dotenv-vault local keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#/!!!!!!!!!!!!!!!!!!!.env.keys!!!!!!!!!!!!!!!!!!!!!!/
#/ DOTENV_KEYs. DO NOT commit to source control /
#/ [how it works](https://dotenv.org/env-keys) /
#/--------------------------------------------------/
DOTENV_KEY_DEVELOPMENT="dotenv://:key_f4516b0077d9aefad9fa7b36cec570e05dcb7cd6d5de1dac2562b6421af7d185@dotenv.local/vault/.env.vault?environment=development"
DOTENV_KEY_PRODUCTION="dotenv://:key_18a137f844e3511022dbf1de2b1bd5e3bd6d1ef4c78988e2521ce9f05abc506a@dotenv.local/vault/.env.vault?environment=production"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;See the pattern?&lt;/strong&gt; A &lt;code&gt;.env.${ENVIRONMENT}&lt;/code&gt; file corresponds to a &lt;code&gt;DOTENV_VAULT_${ENVIRONMENT}&lt;/code&gt; secret and &lt;code&gt;DOTENV_KEY_${ENVIRONMENT}&lt;/code&gt; decryption key.&lt;/p&gt;

&lt;p&gt;Try decrypting the contents of &lt;code&gt;DOTENV_VAULT_PRODUCTION&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx dotenv-vault local decrypt 'dotenv://:key_18a137f844e3511022dbf1de2b1bd5e3bd6d1ef4c78988e2521ce9f05abc506a@dotenv.local/vault/.env.vault?environment=production'
HELLO="production"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! It’s decrypting successfully. Next, let’s put this to use in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Commit &lt;code&gt;.env.vault&lt;/code&gt; to code&lt;/li&gt;
&lt;li&gt;Set DOTENV_KEY on server&lt;/li&gt;
&lt;li&gt;Deploy your code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At runtime your encrypted secrets will be injected into your code just-in-time.&lt;/p&gt;

&lt;p&gt;Try it on your machine with this simple example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ DOTENV_KEY='dotenv://:key_18a137f844e3511022dbf1de2b1bd5e3bd6d1ef4c78988e2521ce9f05abc506a@dotenv.local/vault/.env.vault?environment=production' node index.js

[dotenv@16.3.1][INFO] Loading env from encrypted .env.vault
Hello production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, it loads your env from your encrypted &lt;code&gt;.env.vault&lt;/code&gt; file and successfully outputs &lt;code&gt;Hello production&lt;/code&gt;. Elegant!&lt;/p&gt;

&lt;p&gt;(Other languages are supported too. See &lt;a href="https://dotenv.org/docs"&gt;dotenv.org/docs&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Advantages
&lt;/h2&gt;

&lt;p&gt;Do you remember the &lt;a href="https://techcrunch.com/2023/01/05/circleci-breach/"&gt;CircleCI data breach&lt;/a&gt;? An attacker gained access to everyone’s environment variables putting their software products at major risk.&lt;/p&gt;

&lt;p&gt;But if you were using &lt;code&gt;.env.vault&lt;/code&gt; files, you were not at risk. Why?&lt;/p&gt;

&lt;p&gt;The attacker solely gained access to environment variables, not code. He had your &lt;code&gt;DOTENV_KEY&lt;/code&gt; but not your &lt;code&gt;.env.vault&lt;/code&gt; file. He needed both to access your secrets.&lt;/p&gt;

&lt;p&gt;This takes the &lt;a href="https://12factor.net/config"&gt;Twelve-Factor App&lt;/a&gt;’s principle of &lt;em&gt;strict separation of config from code&lt;/em&gt; to the next level - where even your &lt;em&gt;config&lt;/em&gt; is separated.&lt;/p&gt;

&lt;p&gt;This leads to some great second order effects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are no longer scattering your secrets across multiple third-parties and tools&lt;/li&gt;
&lt;li&gt;Your secrets are easier to manage in one central place close to your code which means less chance of fat-fingering or forgetting to set a secret&lt;/li&gt;
&lt;li&gt;You add more friction to attackers and remove friction for yourself - no more hard work managing secrets across multiple servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’d encourage you to give &lt;code&gt;.env.vault&lt;/code&gt; files a try. I think you will like them after the initial adoption hump. They are simple files that don’t require any additional secret manager processes to be kept running.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.env&lt;/code&gt; files were simple, useful, and added additional security. &lt;code&gt;.env.vault&lt;/code&gt; files maintain that same spirit while adding a much higher level of security. What do you think, let me know at &lt;a href="https://twitter.com/dotenvorg"&gt;@dotenvorg&lt;/a&gt; or &lt;a href="https://twitter.com/motdotla"&gt;@motdotla&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  dotenv-vault — A secrets manager for .env and .env.vault files.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DPX2RhYG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/dotenv-vault-screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DPX2RhYG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.dotenv.org/assets/img/blog/dotenv-vault-screenshot.png" alt="" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are looking to also manage your &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;.env.vault&lt;/code&gt; files across a larger team, complete with permissions, versions, and history then create a &lt;a href="https://dotenv.org"&gt;Dotenv Account&lt;/a&gt;. It’s free with premium features.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dotenv.org/signup"&gt;https://dotenv.org/signup&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotenv</category>
      <category>secrets</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
