<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>configuration &amp;mdash; Simple Engineering</title>
    <link>https://getsimple.works/tag:configuration</link>
    <description></description>
    <pubDate>Fri, 01 May 2026 10:23:01 +0000</pubDate>
    <item>
      <title>How to modularize nodejs application configurations</title>
      <link>https://getsimple.works/how-to-modularize-nodejs-application-configurations?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[The configuration is one of the software component layers, and as such, should be testable in isolation like any other component. Modularization of the configuration layer improves its reusability and testability. The question we should be asking is How do we get there, and that is the objective of this article.&#xA;&#xA;  The 12 App Factor, a collection of good practices, advocates for &#34;strict separation of configuration from code&#34; and &#34;storing configuration in environment variables&#34;, among other things.&#xA;&#xA;The 12 App Factor challenges the status quo, when it comes to configuration management. The following paragraph taken verbatim from the documentation is a clear illustration of that fact. &#xA;&#xA;  &#34;A litmus test for whether an app has all config correctly factored out of the code is whether the codebase could be made open source at any moment, without&#xA;compromising any credentials.&#34; ~ verbatim text from 12 App Factor ~ config section&#xA;&#xA;In this article we will talk about:&#xA;&#xA;Differentiation of configuration layers &#xA;How to decouple code from configuration &#xA;How to modularize configuration for testability&#xA;How to prevent configurations key leaks in public space &#xA;&#xA;  Techniques and ideas discussed in this blog, are available in more detail in &#34;Configurations&#34; chapter of the &#34;Testing nodejs Applications&#34; book. You can grab a copy on this link.  &#xA;&#xA;Show me the code&#xA;&#xA;const Twitter = require(&#39;twitter&#39;);&#xA;&#xA;function TwitterClient() {&#xA;&#xA;    this.client = new Twitter({&#xA;        consumerkey: Plain Text Twitter Consumer Key,&#xA;        consumersecret: Plain Text Twitter Consumer Secret,&#xA;        accesstokenkey: Plain Text Twitter Access Token Key,&#xA;        accesstokensecret: Plain Text Twitter Access Token Secret&#xA;    });&#xA;&#xA;    //accounts such as : @TechCrunch, @Twitter, etc &#xA;    this.track = Array.isArray(accounts) ? accounts.join(&#39;,&#39;) : accounts;&#xA;    //ids: corresponding Twitter Accounts IDs 816653, 783214, etc  &#xA;    this.follow = Array.isArray(ids) ? ids.join(&#39;,&#39;) : ids;&#xA;}&#xA;&#xA;/*&#xA; code&#xA; let stream = new TwitterClient(&#39;@twitter&#39;, &#39;783214&#39;).getStream();&#xA; stream.on(&#39;error&#39;, error =  handleError(error));&#xA; stream.on(&#39;data&#39;, tweet =  logTweet(tweet));&#xA; /code&#xA; @name getStream - Returns Usable Stream&#xA; @returns {ObjectTwitterStream}&#xA; /&#xA;TwitterClient.prototype.getStream = function(){&#xA;    return this.client.stream(&#39;statuses/filter&#39;, {track: this.track, follow: this.follow});&#xA;};&#xA;&#xA;Example:&#xA;&#xA;What can possibly go wrong?&#xA;&#xA;When trying to figure out how to approach modularizing of configurations, the following points may be a challenge:&#xA;&#xA;Being able to share the source code without leaking public keys to the world &#xA;Laying down a strategy to move configurations into configuration files&#xA;Making configuration settings as testable as any module. &#xA;&#xA;The following sections will explore more on making points stated above work. &#xA;&#xA;Layers of configuration of nodejs applications&#xA;&#xA;  Although this blog article provides basic understanding of configuration modularization, it defers configuration management to another blog post: &#34;Configuring nodejs applications&#34;.  &#xA;&#xA;From a production readiness perspective, at least in the context of this blog post, there are two distinct layers of application configurations. &#xA;&#xA;The first layer consists of configurations that nodejs application needs to execute intrinsic business logic. They will be referred to as environment variables/settings. Third-party issued secret keys or server port number configurations, fall under this category. In most cases, you will find such configurations in static variables found in the application. &#xA;&#xA;The second layer consists of configurations required by a system that is going to host the nodejs application. Database server settings, monitoring tools, SSH keys, and other third-party programs running on the hosting entity, are few examples that fall under this category. We will refer to these as system variables/settings. &#xA;&#xA;This blog will be about working with the first layer: environment settings. &#xA;&#xA;Decoupling code from configuration&#xA;&#xA;The first step in decoupling configuration from code is to identify and normalize the way we store our environment variables. &#xA;&#xA;module.exports = function hasSecrets(){&#xA;    const SOMESECRETKEY = &#39;xyz=&#39;;&#xA;    ...&#xA;};&#xA;Example: function with an encapsulated secret&#xA;&#xA;The previous function encapsulates secret values that can be moved outside the application. If we apply this technique, SOMESECRETKEY will be moved outside the function, and imported whenever needed instead. &#xA;&#xA;const SOMESECRETKEY = require(&#34;./config&#34;).SOMESECRETKEY;&#xA;&#xA;module.exports = function hasSecrets(){&#xA;    ...&#xA;};&#xA;Example: function with a decoupled secret value&#xA;&#xA;This process has to be repeated all over the application, till every single secret value is replaced with its constant equivalent. It doesn&#39;t have to be good on the first try, it has simply to work. We can make it better later on. &#xA;&#xA;Configuration modularization &#xA;&#xA;For curiosity&#39;s sake, how does the config.js looks like, after &#34;decoupling configuration from code&#34; step would look like, at the end of the exercise?&#xA;&#xA;export const SOMESECRETKEY = &#39;xyz=&#39;;&#xA;Example: the first iteration of decoupling configuration from code&#xA;&#xA;This step works but has essentially two key flaws:&#xA;&#xA;In a team of multiple players, each player having its own environment variables, the config.js will become a liability. It doesn&#39;t scale that well.  &#xA;This strategy will not prevent catastrophe of leaking the secret to the public, in case the code becomes open source. &#xA;&#xA;To mitigate this, we are going to introduce &#xA;After normalization of the way we store and retrieve environment variables, the next step is how to organize the results in a module. Modules are portable and easy to test. &#xA;&#xA;Modularization makes it possible to test configuration in isolation. Yes, we will have to prove to ourselves it works, before we convince others that it does!&#xA;&#xA;Measures to prevent private key leakage &#xA;&#xA;The first line of defense when it comes to preventing secret keys from leaking to the public is to make sure not a single private value is stored in the codebase itself. The following example illustrates this statement.&#xA;&#xA;module.exports = function leakySecret(){&#xA;    const SOMESECRETKEY = &#39;xyz=&#39;;&#xA;    ...&#xA;};&#xA;Example: function with a leak-able secret key&#xA;&#xA;The second line of defense is to decouple secret values from an integral part of the application, and use an external service to provision secret values at runtime. nodejs makes it possible to read the process content. &#xA;&#xA;A simple yet powerful tool is dotenv library. This library can be swapped, depending on taste or project requirements. &#xA;&#xA;  One of the alternatives to dotenv includes convict.js.   &#xA;&#xA;Last but not least, since we are using git, to add .gitignore prevents contributors to commit their .env files by accident to the shared repository. &#xA;&#xA;  dotenv-extended makes it possible to read nix variables into a dotenv file. &#xA;&#xA;require(&#39;dotenv&#39;).config();&#xA;const Twitter = require(&#39;twitter&#39;);&#xA;&#xA;function TwitterClient(accounts, ids) {&#xA;    this.client = new Twitter({&#xA;        consumerkey: process.env.TWITTERCONSUMERKEY,&#xA;        consumersecret: process.env.TWITTERCONSUMERSECRET,&#xA;        accesstokenkey: process.env.TWITTERACCESSTOKENKEY,&#xA;        accesstokensecret: process.env.TWITTERACCESSTOKENSECRET&#xA;    });&#xA;    ...&#xA;}&#xA;Example*: preventing .env files from being checked into the central repository&#xA;&#xA;Conclusion&#xA;&#xA;Modularization is key to crafting re-usable composable software components. The configuration layer is not an exception to this rule. Modularization of configurations brings elegance, ease of management of critical information such as security keys. &#xA;&#xA;In this article, we re-asserted that with a little bit of discipline, without breaking our piggy bank, it is still possible to better manage application configurations. Modularization of configuration makes it possible to reduce the risk of secret key leaks as well increasing testability readiness. There are additional complimentary materials in the &#34;Testing nodejs applications&#34; book.  &#xA;&#xA;References &#xA;&#xA;Testing nodejs Applications book&#xA;How to store nodejs deployment settings/configuration files? ~ StackOverflow Answer&#xA;Configuring nodejs Web Applications ... Manually || convict.js ~ CompositeCode Blog&#xA;Proxying WebSockets with nginx ~ Chris Lea Blog&#xA;&#xA;tags: #snippets #modularization #nodejs #configuration&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>The configuration is one of the software component layers, and as such, should be testable in isolation like any other component. Modularization of the configuration layer improves its reusability and testability. The question we should be asking is <em>How do we get there</em>, and that is the objective of this article.</p>

<blockquote><p>The <a href="https://12factor.net/config">12 App Factor</a>, a collection of good practices, advocates for <em>“strict separation of configuration from code”</em> and <em>“storing configuration in environment variables”</em>, among other things.</p></blockquote>

<p>The <em><a href="https://12factor.net/config">12 App Factor</a></em> challenges the <em>status quo</em>, when it comes to configuration management. The following paragraph taken <em>verbatim</em> from the documentation is a clear illustration of that fact.</p>

<blockquote><p>“A litmus test for whether an app has all config correctly factored out of the code is whether the codebase could be made open source at any moment, without
compromising any credentials.” ~ verbatim text from <a href="https://12factor.net/config">12 App Factor ~ config section</a></p></blockquote>

<p><strong><em>In this article we will talk about:</em></strong></p>
<ul><li>Differentiation of configuration layers</li>
<li>How to decouple code from configuration</li>
<li>How to modularize configuration for testability</li>
<li>How to prevent configurations key leaks in public space</li></ul>

<blockquote><p>Techniques and ideas discussed in this blog, are available in more detail in <a href="https://bit.ly/2ZFJytb"><strong>“Configurations” chapter of the “Testing <code>nodejs</code> Applications”</strong></a> book. <a href="https://bit.ly/2ZFJytb">You can grab a copy on this link</a>.</p></blockquote>

<h2 id="show-me-the-code" id="show-me-the-code">Show me the code</h2>

<pre><code class="language-JavaScript">const Twitter = require(&#39;twitter&#39;);

function TwitterClient() {

    this.client = new Twitter({
        consumer_key: `Plain Text Twitter Consumer Key`,
        consumer_secret: `Plain Text Twitter Consumer Secret`,
        access_token_key: `Plain Text Twitter Access Token Key`,
        access_token_secret: `Plain Text Twitter Access Token Secret`
    });

    //accounts such as : @TechCrunch, @Twitter, etc 
    this.track = Array.isArray(accounts) ? accounts.join(&#39;,&#39;) : accounts;
    //ids: corresponding Twitter Accounts IDs 816653, 783214, etc  
    this.follow = Array.isArray(ids) ? ids.join(&#39;,&#39;) : ids;
}

/**
 * &lt;code&gt;
 * let stream = new TwitterClient(&#39;@twitter&#39;, &#39;783214&#39;).getStream();
 * stream.on(&#39;error&#39;, error =&gt; handleError(error));
 * stream.on(&#39;data&#39;, tweet =&gt; logTweet(tweet));
 * &lt;/code&gt;
 * @name getStream - Returns Usable Stream
 * @returns {Object&lt;TwitterStream&gt;}
 */
TwitterClient.prototype.getStream = function(){
    return this.client.stream(&#39;statuses/filter&#39;, {track: this.track, follow: this.follow});
};

</code></pre>

<p><em><em>Example</em>:</em></p>

<h2 id="what-can-possibly-go-wrong" id="what-can-possibly-go-wrong">What can possibly go wrong?</h2>

<p>When trying to figure out how to approach modularizing of configurations, the following points may be a challenge:</p>
<ul><li>Being able to share the source code without leaking public keys to the world</li>
<li>Laying down a strategy to move configurations into configuration files</li>
<li>Making configuration settings as testable as any module.</li></ul>

<p>The following sections will explore more on making points stated above work.</p>

<h2 id="layers-of-configuration-of-nodejs-applications" id="layers-of-configuration-of-nodejs-applications">Layers of configuration of <code>nodejs</code> applications</h2>

<blockquote><p>Although this blog article provides basic understanding of configuration modularization, it defers configuration management to another blog post: <strong>“<a href="./how-to-configure-nodejs-applications">Configuring <code>nodejs</code> applications”</a></strong>.</p></blockquote>

<p>From a production readiness perspective, at least in the context of this blog post, there are two distinct layers of application configurations.</p>

<p>The first layer consists of configurations that <code>nodejs</code> application needs to execute intrinsic business logic. They will be referred to as <em>environment variables/settings</em>. Third-party issued secret keys or server port number configurations, fall under this category. In most cases, you will find such configurations in static variables found in the application.</p>

<p>The second layer consists of configurations required by a system that is going to host the <code>nodejs</code> application. Database server settings, monitoring tools, SSH keys, and other third-party programs running on the hosting entity, are few examples that fall under this category. We will refer to these as <em>system variables/settings</em>.</p>

<p>This blog will be about working with the first layer: <em>environment settings</em>.</p>

<h2 id="decoupling-code-from-configuration" id="decoupling-code-from-configuration">Decoupling code from configuration</h2>

<p>The first step in decoupling configuration from code is to identify and normalize the way we store our environment variables.</p>

<pre><code class="language-JavaScript">module.exports = function hasSecrets(){
    const SOME_SECRET_KEY = &#39;xyz=&#39;;
    ...
};
</code></pre>

<p><em><em>Example</em>: function with an encapsulated secret</em></p>

<p>The previous function encapsulates secret values that can be moved outside the application. If we apply this technique, <code>SOME_SECRET_KEY</code> will be moved outside the function, and imported whenever needed instead.</p>

<pre><code class="language-JavaScript">const SOME_SECRET_KEY = require(&#34;./config&#34;).SOME_SECRET_KEY;

module.exports = function hasSecrets(){
    ...
};
</code></pre>

<p><em><em>Example</em>: function with a decoupled secret value</em></p>

<p>This process has to be repeated all over the application, till every single secret value is replaced with its constant equivalent. It doesn&#39;t have to be good on the first try, it has simply to work. We can make it better later on.</p>

<h2 id="configuration-modularization" id="configuration-modularization">Configuration modularization</h2>

<p>For curiosity&#39;s sake, how does the <code>config.js</code> looks like, after <em>“decoupling configuration from code”</em> step would look like, at the end of the exercise?</p>

<pre><code class="language-JavaScript">export const SOME_SECRET_KEY = &#39;xyz=&#39;;
</code></pre>

<p><em><em>Example</em>: the first iteration of decoupling configuration from code</em></p>

<p>This step works but has essentially two key flaws:</p>
<ul><li>In a team of multiple players, each player having its own environment variables, the <code>config.js</code> will become a liability. It doesn&#39;t scale that well.<br/></li>
<li>This strategy will not prevent <em>catastrophe</em> of leaking the secret to the public, in case the code becomes open source.</li></ul>

<p>To mitigate this, we are going to introduce
After normalization of the way we store and retrieve environment variables, the next step is how to organize the results in a module. Modules are portable and easy to test.</p>

<p>Modularization makes it possible to test configuration in isolation. Yes, we will have to prove to ourselves it works, before we convince others that it does!</p>

<h2 id="measures-to-prevent-private-key-leakage" id="measures-to-prevent-private-key-leakage">Measures to prevent private key leakage</h2>

<p>The first line of defense when it comes to preventing secret keys from leaking to the public is to make sure not a single private value is stored in the codebase itself. The following example illustrates this statement.</p>

<pre><code class="language-JavaScript">module.exports = function leakySecret(){
    const SOME_SECRET_KEY = &#39;xyz=&#39;;
    ...
};
</code></pre>

<p><em><em>Example</em>: function with a leak-able secret key</em></p>

<p>The second line of defense is to decouple secret values from an integral part of the application, and use an external service to provision secret values at runtime. <code>nodejs</code> makes it possible to read the <code>process</code> content.</p>

<p>A simple yet powerful tool is <code>dotenv</code> library. This library can be swapped, depending on taste or project requirements.</p>

<blockquote><p>One of the alternatives to <code>dotenv</code> includes <code>convict.js</code>.</p></blockquote>

<p>Last but not least, since we are using <code>git</code>, to add <code>.gitignore</code> prevents contributors to commit their <code>.env</code> files by accident to the shared repository.</p>

<blockquote><p><a href="https://github.com/keithmorris/node-dotenv-extended"><code>dotenv-extended</code></a> makes it possible to read *nix variables into a <code>dotenv</code> file.</p></blockquote>

<pre><code class="language-JavaScript">require(&#39;dotenv&#39;).config();
const Twitter = require(&#39;twitter&#39;);

function TwitterClient(accounts, ids) {
    this.client = new Twitter({
        consumer_key: process.env.TWITTER_CONSUMER_KEY,
        consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
        access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY,
        access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
    });
    ...
}
</code></pre>

<p><em><em>Example</em>: preventing <code>.env</code> files from being checked into the central repository</em></p>

<h2 id="conclusion" id="conclusion">Conclusion</h2>

<p>Modularization is key to crafting re-usable composable software components. The configuration layer is not an exception to this rule. Modularization of configurations brings elegance, ease of management of critical information such as security keys.</p>

<p>In this article, we re-asserted that with a little bit of discipline, without breaking our piggy bank, it is still possible to better manage application configurations. Modularization of configuration makes it possible to reduce the risk of secret key leaks as well increasing testability readiness. There are additional complimentary materials in the <strong><a href="https://bit.ly/2ZFJytb">“Testing <code>nodejs</code> applications”</a></strong> book.</p>

<h2 id="references" id="references">References</h2>
<ul><li><a href="https://bit.ly/2ZFJytb">Testing <code>nodejs</code> Applications book</a></li>
<li>How to store <code>nodejs</code> deployment settings/configuration files? ~ <a href="https://stackoverflow.com/a/5870544/132610">StackOverflow Answer</a></li>
<li>Configuring <code>nodejs</code> Web Applications ... Manually || <code>convict.js</code> ~ <a href="https://compositecode.com/2014/03/15/configuring-node-js-web-applications/">CompositeCode Blog</a></li>
<li>Proxying WebSockets with <code>nginx</code> ~ <a href="https://chrislea.com/2013/02/23/proxying-websockets-with-nginx/">Chris Lea Blog</a></li></ul>

<p>tags: <a href="https://getsimple.works/tag:snippets" class="hashtag"><span>#</span><span class="p-category">snippets</span></a> <a href="https://getsimple.works/tag:modularization" class="hashtag"><span>#</span><span class="p-category">modularization</span></a> <a href="https://getsimple.works/tag:nodejs" class="hashtag"><span>#</span><span class="p-category">nodejs</span></a> <a href="https://getsimple.works/tag:configuration" class="hashtag"><span>#</span><span class="p-category">configuration</span></a></p>
]]></content:encoded>
      <guid>https://getsimple.works/how-to-modularize-nodejs-application-configurations</guid>
      <pubDate>Thu, 17 Jun 2021 06:20:09 +0000</pubDate>
    </item>
  </channel>
</rss>