DEV Community

Cover image for NextJS - Get rid of DotENV
Deiring Andreas
Deiring Andreas

Posted on • Updated on

NextJS - Get rid of DotENV

I always disliked the .env file. Almost every time I was forced to place it on the top level of my app directory. At some point i started to use the npm config package. This gives the application a consistent configuration interface and there is a formidable way to implement it into the NextJS environment. For people which prefer code over text, feel free to checkout the finished implementation.


As reference we usa a NextJS Typescript zero configuration setup.

npx create-next-app@latest --ts
# or
yarn create next-app --typescript
Enter fullscreen mode Exit fullscreen mode

First we have to install the necessary npm package.

npm install config @types/config
Enter fullscreen mode Exit fullscreen mode

Now we create the config directory and configuration files. The default.yaml will be used later as a type template.

- default.yaml
- development.yaml
- production.yaml
Enter fullscreen mode Exit fullscreen mode

NextJS has the possibility to define environment variables in the config file. To make full use of it, we will import the config package and set the environment variables to the configuration variables with config.util.toObject(). By default NextJS creates a next.config.js file in the root directory. Change the extension to .mjs and replace the content with the following.

// next.config.mjs

import config from 'config';

const nextConfig = {
  reactStrictMode: true,
  env: config.util.toObject()
Enter fullscreen mode Exit fullscreen mode

At this point we already replaced the .env files. NextJS will load the configuration files from the config folder with the corresponding activ environment.

To use it with typescript we have to do some additional work. First we will need a type declaration file for the config variables. Then we have to add it to the global process environment.

From here on out we will work with an example for better traceability.
Let us put some stuff into the default.yaml file.

  apiKey: apiKey
  appId: appId
  projectId: projectId
  authDomain: authDomain
  databaseURL: databaseURL
  storageBucket: storageBucket
  messagingSenderId: messagingSenderId
  measurementId: measurementId
Enter fullscreen mode Exit fullscreen mode

Next we will have to reflect the configuration variables in typescript. In my native language there is a saying:

Viele Wege führen nach Rom

In short it means there are many solutions for a problem. For example, we could do it manually or use a web based yaml to typescript converter. Unfortunately i could not find any npm package for this problem. But as many of us know: Why do something in 10 minutes when you can automate it in 10 hours? Consequently, let us install an additional package.

npm install -D ymlts
Enter fullscreen mode Exit fullscreen mode

Now we can convert the configuration file to typescript from our console. With the following command we create the necessary type file.

npx ymlts config/default @types/config 
Enter fullscreen mode Exit fullscreen mode

This will create a config.d.ts in the @types directory. Its content should look like this.

// @types/config.d.ts

interface Config {
    firebase: Firebase;

interface Firebase {
    apiKey:            string;
    appId:             string;
    projectId:         string;
    authDomain:        string;
    databaseURL:       string;
    storageBucket:     string;
    messagingSenderId: string;
    measurementId:     string;
Enter fullscreen mode Exit fullscreen mode

Last but not least, we have to add the new config type to the process environment. For this we create a global.d.ts file in the @types directory...

- global.d.ts
Enter fullscreen mode Exit fullscreen mode

...and extend the process environment with the config type.

// @types/global.d.ts

namespace NodeJS {
  interface ProcessEnv extends Config { }
Enter fullscreen mode Exit fullscreen mode

For future use, if you are really lazy: It is possible to add the ymlts command to the package.json and start it with npm run env.

// package.json

"scripts": {
  "env": "npx ymlts config/default @types/config",
Enter fullscreen mode Exit fullscreen mode


So why? At first glance this looks like unnecessary work, but there is some neat stuff!

  • Better readability with a humanfriendly YAML file.

  • Environment variables managed in an organized config folder.

  • Normaly you have to prefix Environment Variables with NEXT_PUBLIC_ to expose them to the browser. But NextJS replaces Environment Variables at buildtime which should make it obsolete.

  • By converting the config file to types we get the possibility to use intellisense with process.env.

  • The YAML configuration variables can be nested. Related to this blog as example it is possible to initialize the Firebase app with initializeApp(process.env.firebase);.

Top comments (0)