IsaIkari
IsaIkari

Reputation: 1154

Update attributes in .env file in Node JS

I am wrting a plain .env file as following:

VAR1=VAL1
VAR2=VAL2

I wonder if there's some module I can use in NodeJS to have some effect like :

somefunction(envfile.VAR1) = VAL3

and the resulted .env file would be

VAR1=VAL3
VAR2=VAL2

i.e., with other variables unchanged, just update the selected variable.

Upvotes: 8

Views: 11190

Answers (5)

Lucas Mendonca
Lucas Mendonca

Reputation: 436

By using the RegExp constructor we can achieve an even smaller solution than the accepted answer while also fixing the prefix problem mentioned by jp06:

const fs = require("fs");

function setEnvValue(key, value) {
    const file = fs.readFileSync(".env", "utf8");

    // ^ Matches the start of a line due to the 'm' multiline flag
    // = Matches the literal equal sign character
    // .+ Matches any set of characters except for newlines
    const newFile = file.replace(new RegExp(`^${key}=.+`, 'm'), `${key}=${newValue}`);
    
    fs.writeFileSync(".env", newFile);
}

setEnvValue("A", "1");

Upvotes: 0

Marcos Viana
Marcos Viana

Reputation: 171

Simple and it works: for typescript

import fs from 'fs'
import os from 'os'
import path from 'path'

function setEnvValue(key: string, value: string): void {
    const environment_path = path.resolve('config/environments/.env.test')
    const ENV_VARS = fs.readFileSync(environment_path, 'utf8').split(os.EOL)

    const line = ENV_VARS.find((line: string) => {
        return line.match(`(?<!#\\s*)${key}(?==)`)
    })

    if (line) {
        const target = ENV_VARS.indexOf(line as string)
        if (target !== -1) {
            ENV_VARS.splice(target, 1, `${key}=${value}`)
        } else {
            ENV_VARS.push(`${key}=${value}`)
        }
    }

    fs.writeFileSync(environment_path, ENV_VARS.join(os.EOL))
}

Upvotes: 1

jp06
jp06

Reputation: 335

I think the accepted solution will suffice for most use cases, but I encountered a few problems while using it personally:

  • It will match keys that is prefixed with your target key if it is found first (e.g. if ENV_VAR is the key, ENV_VAR_FOO is also a valid match).
  • If the key does not exist in your .env file, it will replace the last line of your .env file. In my case, I wanted to do an upsert instead of just updating existing env var.
  • It will match commented lines and update them.

I modified a few things from Marc's answer to solve the above problems:

function setEnvValue(key, value) {
  // read file from hdd & split if from a linebreak to a array
  const ENV_VARS = fs.readFileSync(".env", "utf8").split(os.EOL);

  // find the env we want based on the key
  const target = ENV_VARS.indexOf(ENV_VARS.find((line) => {
    // (?<!#\s*)   Negative lookbehind to avoid matching comments (lines that starts with #).
    //             There is a double slash in the RegExp constructor to escape it.
    // (?==)       Positive lookahead to check if there is an equal sign right after the key.
    //             This is to prevent matching keys prefixed with the key of the env var to update.
    const keyValRegex = new RegExp(`(?<!#\\s*)${key}(?==)`);

    return line.match(keyValRegex);
  }));

  // if key-value pair exists in the .env file,
  if (target !== -1) {
    // replace the key/value with the new value
    ENV_VARS.splice(target, 1, `${key}=${value}`);
  } else {
    // if it doesn't exist, add it instead
    ENV_VARS.push(`${key}=${value}`);
  }

  // write everything back to the file system
  fs.writeFileSync(".env", ENV_VARS.join(os.EOL));
}

Upvotes: 9

Marc
Marc

Reputation: 3894

You can use the fs, os module and some basic array/string operations.

const fs = require("fs");
const os = require("os");


function setEnvValue(key, value) {

    // read file from hdd & split if from a linebreak to a array
    const ENV_VARS = fs.readFileSync("./.env", "utf8").split(os.EOL);

    // find the env we want based on the key
    const target = ENV_VARS.indexOf(ENV_VARS.find((line) => {
        return line.match(new RegExp(key));
    }));

    // replace the key/value with the new value
    ENV_VARS.splice(target, 1, `${key}=${value}`);

    // write everything back to the file system
    fs.writeFileSync("./.env", ENV_VARS.join(os.EOL));

}


setEnvValue("VAR1", "ENV_1_VAL");

.env

VAR1=VAL1
VAR2=VAL2
VAR3=VAL3

Afer the executen, VAR1 will be ENV_1_VAL

No external modules no magic ;)

Upvotes: 23

IsaIkari
IsaIkari

Reputation: 1154

var updateAttributeEnv = function(envPath, attrName, newVal){
    var dataArray = fs.readFileSync(envPath,'utf8').split('\n');

    var replacedArray = dataArray.map((line) => {
        if (line.split('=')[0] == attrName){
            return attrName + "=" + String(newVal);
        } else {
            return line;
        }
    })

    fs.writeFileSync(envPath, "");
    for (let i = 0; i < replacedArray.length; i++) {
        fs.appendFileSync(envPath, replacedArray[i] + "\n"); 
    }
}

I wrote this function to solve my issue.

Upvotes: 0

Related Questions