There's a lot of confusion about this topic and in these answers. I'm not surprised, that no single answer was accepted. Hopefully yet.
The answer by Basheer indeed solves most of the problems. However, there are few things you still need to know. Especially, if you're coming, like me, from frontend background and wants to add secrets to your frontend. Possibly, related to the introduction of some Server-Side Rendering (SSR) logic in the app.
Most probably you've seen this code in your webpack
settings in a frontend app to solve the issue, as a frontend developer.
/* Custom webpack properties. */
const dotenv = require('dotenv-webpack');
module.exports = {
plugins: [
new dotenv(), // Handle environemntal variables on localhost, but on the Server-Side Rendering (SSR). There's no access to "process.env" on the browser.
],
};
Now, it'll work out fine, if you render on the server (SSR) across your app if the .env
file is in the root of your project. However, it might not work if you have some custom server-related settings. An example of such situation is Angular Universal
, Nuxt.js
handles this much easier in which require('dotenv').config()
in your next.config.js
and makes you good to go. That's due to difference in philosophies between how Angular
and Vue.js
are handling SSR. To get Angular Universal
app from Angular
that's just 1 command, but the SSR app isn't as nicely organized as Nuxt.js
. It comes with a price that to generate Nuxt.js
app from Vue.js
, you basically have to generate a new Nuxt.js
project and copy files due to quite some differences between Nuxt.js
and Vue.js
setup. Don't know how React
/Next.js
and Svelte
/Sapper
solves this, but if similarly to Angular
then you also might consider reading further.
Now, you've some server-related logic in a separated folder called server and let say the file is called main.ts
. Maybe apart SSR in that file, you can also have sending mail (nodemailer
?) logic. Then you'd like to use process.env
, but apparently it doesn't work, even though you have the logic defined in webpack
. That's where the require('dotenv').config();
is needed, even if you're using different syntax for import (such as import { Express } from 'express';
for example), require('dotenv').config();
will work like that. Don't feel confused. As long as .env
is in the root of your app (don't confuse with server
folder) and the variables have correct syntax inside that file, e.g.
MAIL_ACCOUNT=mymail@mydomain.com
MAIL_HOST=smtp.mydomain.com
MAIL_PORT=587
It'll work.
Last scenario, in the SSR app you realised that to host this app you need something called Serverless/Cloud Functions/FaaS. Here, I know only Firebase
scenario. In your project, to deploy such app you might have functions
folder, from which you deploy the SSR app to the Cloud Functions for Firebase
, in this example. What a surprise, on a deployment mail is not working and after hours of figuring out what's happening in the logs you can see process.env.VARIABLE_NAME returning undefined
. The reason is that as of today the CLI cannot merge files from other locations and indeed the .env file has to be manually copied to the functions folder. Once copy/paste the .env
file to functions
and deploy, it'll work.
What you can use for debugging is one of those:
console.log(require('dotenv').config());
console.log(require('dotenv').config({debug: true}));
However, be careful with your secrets, because these will be revealed when your .env
setup will be done. Trying to access one of the secrets and trying to log its value in the logs might be more secure option. Especially, if you have many secrets and don't want to rewrite all.
Hope so this one post will cover most of the scenarios.