<?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: Matt</title>
    <description>The latest articles on DEV Community by Matt (@mjrowles).</description>
    <link>https://dev.to/mjrowles</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%2F169936%2Fa1c5f5eb-8b0f-4b33-afe0-7a9a7cabdd68.png</url>
      <title>DEV Community: Matt</title>
      <link>https://dev.to/mjrowles</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mjrowles"/>
    <language>en</language>
    <item>
      <title>A better way to do environment variables</title>
      <dc:creator>Matt</dc:creator>
      <pubDate>Wed, 06 Mar 2024 22:05:12 +0000</pubDate>
      <link>https://dev.to/mjrowles/a-better-way-to-do-environment-variables-aje</link>
      <guid>https://dev.to/mjrowles/a-better-way-to-do-environment-variables-aje</guid>
      <description>&lt;p&gt;Running software will always require configuration values to declaratively steer the outcome of its functionality.&lt;/p&gt;

&lt;p&gt;We have traditionally utilised environment variables to handle all of our important values. Whilst it works and there are benefits, it has become a very inflexible way to build software in light of evolved patterns.&lt;/p&gt;

&lt;p&gt;Using things like secrets manager services, feature flag services and config files, we can accelerate our development with more confidence and care.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vk44tbefnkvq28mg1jc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vk44tbefnkvq28mg1jc.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;a href="https://www.pexels.com/photo/photo-of-man-surfing-on-ocean-waves-2607830/"&gt;Bondi, Larry Snickers&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Current State &amp;amp; Criticisms
&lt;/h1&gt;

&lt;p&gt;Take this example snippet from a small imaginary TypeScript monorepo consisting of a website using Vite-config, Node backend and utilising environment variables to manage all build-time and runtime outcomes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.env.staging&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: assume this will be set properly upon deployment and not using files&lt;/em&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;ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;staging
&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
&lt;span class="nv"&gt;VITE_TITLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Medium"&lt;/span&gt;
&lt;span class="nv"&gt;FEATURE_1_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="nv"&gt;SOME_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xxx
&lt;span class="nv"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;api.medium.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;api.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;FEATURE_1_ENABLED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SOME_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;app.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;VITE_TITLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a closer look at the environment variables:&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="c"&gt;# required at build-time, boot-time &amp;amp; runtime&lt;/span&gt;
&lt;span class="c"&gt;# because of this, values like these will always need to be environment &lt;/span&gt;
&lt;span class="c"&gt;# variables&lt;/span&gt;
&lt;span class="nv"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;staging
&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production

&lt;span class="c"&gt;# static, frontend-only &amp;amp; non-sensitive values&lt;/span&gt;
&lt;span class="nv"&gt;VITE_TITLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Medium"&lt;/span&gt;
&lt;span class="nv"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;api.medium.staging

&lt;span class="c"&gt;# this is a non-sensitive, runtime boolean value&lt;/span&gt;
&lt;span class="c"&gt;# feature flags should ideally be dynamic and personalised&lt;/span&gt;
&lt;span class="nv"&gt;FEATURE_1_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# this is a sensitive runtime value&lt;/span&gt;
&lt;span class="nv"&gt;SOME_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks fine, so what are the drawbacks here?&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Experience &amp;amp; Confidence
&lt;/h2&gt;

&lt;p&gt;You could imagine in a large complex product, this file could move into the 100's of lines. Now multiply this by the amount of environments you have and things can more easily go wrong. These are testable, of course, but since they are coming from the environment the tests are being run in, rather than the code or a service, it's environment dependent.&lt;/p&gt;

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

&lt;p&gt;Yes, someone needs access to your server to see these values. What if someone is testing a production build locally and accidentally commits a secret value? Some IDE's store local history for weeks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static vs Dynamic
&lt;/h2&gt;

&lt;p&gt;Changing environment variables on a server is the only option we have here and will require a service restart in most cases, whilst 'feature flag' type values should have the ability to be dynamically changed on the fly i.e., from an admin interface or be personalised for workspaces or users through a session variable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;Where do these values get set? For local dev, it's right in front of us, but when we deploy our environment, we begin to set most of these in some separate platform, like a CI/CD pipeline config, which is away from our codebase and becomes a bit of a black box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb7zzu3so05xcecwo8du.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb7zzu3so05xcecwo8du.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;a href="https://www.pexels.com/photo/people-gathering-near-swimming-pool-785065/"&gt;Icebergs, Belle Co&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;tl;dr do these steps&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Categorise&lt;/strong&gt; your values:&lt;br&gt;
i. environment values&lt;br&gt;
ii. secret values&lt;br&gt;
iii. non-secret values&lt;br&gt;
iv. dynamic &amp;amp; personalised values&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use a &lt;strong&gt;typed environment variable file&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use a &lt;strong&gt;secrets manager&lt;/strong&gt; service&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;strong&gt;code config files&lt;/strong&gt; that are apart of your codebase (file per environment)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use a &lt;strong&gt;feature flag&lt;/strong&gt; service&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's go deeper!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Categorising values
&lt;/h2&gt;

&lt;p&gt;This will help you understand where you should move your existing environment variables to.&lt;/p&gt;

&lt;h3&gt;
  
  
  i. Environment Values
&lt;/h3&gt;

&lt;p&gt;Environment values are values that declaratively tell the service or app how it should run in the given environment.&lt;/p&gt;

&lt;h4&gt;
  
  
  Traits
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;required at build time&lt;/li&gt;
&lt;li&gt;required at boot time&lt;/li&gt;
&lt;li&gt;often required during runtime&lt;/li&gt;
&lt;li&gt;not sensitive&lt;/li&gt;
&lt;li&gt;immutable&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;environment determinant e.g., Node Environment is production &lt;code&gt;NODE_ENV=production&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ii. Secret values
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Traits
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;sometimes required at build time&lt;/li&gt;
&lt;li&gt;required at boot time&lt;/li&gt;
&lt;li&gt;required during runtime&lt;/li&gt;
&lt;li&gt;sensitive&lt;/li&gt;
&lt;li&gt;potentially mutable, generally immutable&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;third-party API keys e.g., Stripe API Key &lt;code&gt;STRIPE_API_KEY=abc-123&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  iii. Static, non-secret values
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Traits
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;required at build time&lt;/li&gt;
&lt;li&gt;required during runtime&lt;/li&gt;
&lt;li&gt;not sensitive&lt;/li&gt;
&lt;li&gt;potentially mutable, generally immutable&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;UI content variables e.g., meta page title &lt;code&gt;PAGE_TITLE=My Website&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Feature flag value e.g., toggling a new feature on in certain environment &lt;code&gt;NEW_SEARCH_BAR_UI_ENABLED=false&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  iv. Dynamic, personalised values
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Traits
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;required at build time&lt;/li&gt;
&lt;li&gt;required during runtime&lt;/li&gt;
&lt;li&gt;not sensitive&lt;/li&gt;
&lt;li&gt;mutable&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Feature previews e.g., subset of organisations in your app can preview a new feature before the rest of the users can e.g., &lt;code&gt;NEW_SEARCH_BAR_UI_ENABLED=true&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Use a typed environment variable file
&lt;/h2&gt;

&lt;p&gt;Let's say this is what our environment variables look like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment (however you set this):&lt;/strong&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;DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false
&lt;/span&gt;&lt;span class="nv"&gt;DEPLOYMENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;staging
&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we will always need some values from the environment, the least we can do is wrap some strictness around the types for confidence.&lt;/p&gt;

&lt;p&gt;Using TypeScript as an example, we can create an &lt;code&gt;environment.d.ts&lt;/code&gt; file so we get completion and type safety when accessing &lt;code&gt;process.env&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;environment.d.ts:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;NodeJS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ProcessEnv&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;DEPLOYMENT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that they are all &lt;code&gt;string | undefined&lt;/code&gt; in Typescript, whether or not you have assigned these to a number, boolean or otherwise, e.g.,&lt;/p&gt;

&lt;p&gt;✅ &lt;code&gt;if (process.env.DEBUG === 'false') { ...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;❌ &lt;code&gt;if (!process.env.DEBUG) { ...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lostfictions/znv"&gt;znv&lt;/a&gt; is pretty good at improving the types of your environment also.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Secrets Manager service
&lt;/h2&gt;

&lt;p&gt;I would suggest starting with these as environment variables as they change infrequently.&lt;/p&gt;

&lt;p&gt;However, there may come a time where you want these to be dynamic, in the sense that you want to change them without incurring any downtime. For this, we can use a Secrets Manager service.&lt;/p&gt;

&lt;p&gt;Off the shelf Secret Manager services can get expensive, so you may want to roll your own, however, the responsibility of designing the encryption process, accessor patterns and probably an admin UI now rely with your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Config files
&lt;/h2&gt;

&lt;p&gt;When infrastructure-as-a-service and infrastructure-as-code became a reality, there was a notion that we could have 1..n environments. Whilst this is still true, things like feature flagging helped us move code to production in a safer manner, since we could obfuscate new features from users until they were ready and still deliver new features, fixes and technical refreshes.&lt;/p&gt;

&lt;p&gt;With this paradigm shift, lot's of teams moved toward &lt;a href="https://trunkbaseddevelopment.com"&gt;trunk-based development&lt;/a&gt;. In doing so, we have come full-circle in a way, way back to a time where we had multiple physical servers for the various stages of SDLC; staging and production. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;staging&lt;/strong&gt;: production-like environment where we can sanity test new code. This generally reflects the code in &lt;code&gt;main&lt;/code&gt; before production does.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;production&lt;/strong&gt;: the thing customers use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additional environments can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;development&lt;/strong&gt;: a safe space to perform architecture or third-party changes without disrupting the flow of all code to production. This is generally for developers only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;local&lt;/strong&gt;: for local development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;test&lt;/strong&gt;: for test-running environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given the above, we can have configuration files which store safe values for each environment using types:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: as this grows, separate files would be welcome&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;config/getConfigValue.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// we can separate this into a `staging.ts` file&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;staging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ConfigKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;PAGE_TITLE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My website&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;NEW_SEARCH_BAR_UI_ENABLED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// we can separate this into a `production.ts` file&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ConfigKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;PAGE_TITLE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My website&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;NEW_SEARCH_BAR_UI_ENABLED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// type safe config&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ConfigKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;PAGE_TITLE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;NEW_SEARCH_BAR_UI_ENABLED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;ConfigKeys&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// we can add as many environments as we need, even a 'default' environment for fallback (although this could be production for safe use in most cases)&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DeploymentEnvironment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;staging&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ConfigKeysForEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DeploymentEnvironment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ConfigKeys&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;configKeysForEnv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ConfigKeysForEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;staging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getConfigValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;deploymentEnvironment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DeploymentEnvironment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;override&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ConfigKeys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ConfigKeys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deployment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;deploymentEnvironment&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deployment&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;configKeysForEnv&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s2"&gt;`Unsupported deployment environment provided for config: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;deploymentEnvironment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;configKeysForEnv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;deployment&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s2"&gt;`Config key does not exist for deployment environment: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;override&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah yeah, development 'code' next to production 'code', there are trade-offs.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Feature Flag service
&lt;/h2&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Let me know how you go moving away from using environment variables for everything.&lt;/p&gt;

&lt;p&gt;Please feel free to leave any feedback as I'm always happy to chat about different opinions &amp;amp; experiences and learn new things.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: I like using a common image theme for my posts so whilst Bondi makes no sense in a technical blog, nerd talk and code by itself would be boring.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Downsides to this, multi language environment will need to incorporate independent implementations per language. Whilst I can say this is the cost of doing business, properly, this is overhead&lt;br&gt;
Security&lt;br&gt;
Testable&lt;br&gt;
testing production out locally&lt;br&gt;
let's other people in your team who are not technical manage the commercial side of the product re: feature flags&lt;br&gt;
production secrets being committed&lt;/p&gt;

&lt;p&gt;I might be a minority and a bit bias, but low code / no-code solutions generally irk me and I would often suggest avoiding them. Like tennis, playing in the middle is risky.&lt;/p&gt;

&lt;p&gt;but but but development values in production and vice versa&lt;/p&gt;

&lt;p&gt;Run time will pick up env var change&lt;/p&gt;

&lt;p&gt;Overrides for an env in db (singleton table) and overrides at workspace and even user level&lt;/p&gt;

&lt;p&gt;Current impls&lt;/p&gt;

&lt;p&gt;Dev has changed due to this evolution&lt;/p&gt;

&lt;p&gt;Low code no code sucks&lt;/p&gt;

&lt;p&gt;Dynamic data &amp;gt; low code&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>devops</category>
      <category>typescript</category>
    </item>
    <item>
      <title>The best get better all the time 💫</title>
      <dc:creator>Matt</dc:creator>
      <pubDate>Thu, 09 Jan 2020 08:54:20 +0000</pubDate>
      <link>https://dev.to/mjrowles/the-best-get-better-all-the-time-3lf7</link>
      <guid>https://dev.to/mjrowles/the-best-get-better-all-the-time-3lf7</guid>
      <description>&lt;p&gt;Every team’s continued success is up to how much they keep improving their people, processes and product/s.&lt;/p&gt;

&lt;p&gt;Continuous improvement can be difficult for even the most refined and experienced of teams and this can be due to many things; time constraints, execution, following through on actions and so on. &lt;/p&gt;

&lt;p&gt;We’re building a platform that helps teams practice continuous improvement seamlessly within your iterations so you can deliver only the best value for our customers.&lt;/p&gt;

&lt;p&gt;Starting with a &lt;a href="https://www.bebetter.team"&gt;free retro tool&lt;/a&gt;, the team at Better have lot’s of plans  to help make your team keep on improving, such as automation and integrations, so stay tuned over the coming months.&lt;/p&gt;

&lt;p&gt;In the meantime, we’re always happy to hear your feedback, so please let us know what you think so far and what you’d like to see next!&lt;/p&gt;

</description>
      <category>agile</category>
      <category>saas</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
