Next.js Environment Variable Support and the .env.local File

Sunday, February 19, 2023 at 12:04 PM | 4 min read

Last modified on Monday, June 1, 2026 at 11:24 AM

#nextjs, #environment variables, #fullstack development

Tree supported by large wooden hand

Photo by Neil Thomas on Unsplash

Table of Contents

Note 5.31.26: The current version of Next.js has changed since the original publication of this post. When it was published in February 2023, Next.js 13+ < 13.4 was the current version. Next.js 13.4 was released in May 2023. Now I am at Next.js 16.2.6. Environment variables are still supported, but the way they are loaded and accessed has changed. These changes were introduced in Next.js 15 which was released in October 2024. The biggest change was the introduction of @next/env, which replaced next/env. next/env was introduced in Next.js 12 which was released October 26, 2021.I built my interglobalmedia-tailwind-nextjs application with it. I had to use environment variables in my interglobalmedia-tailwind-nextjs application because I used Plausible analytics, Giscus comments, and ConvertKit, all of which needed to be exposed in the browser in order to work. I did not need to use environment variables to store any sensitive information. I am currently not using any environment variables here. To learn more about the newer @next/env introduced in Next.js 15, please visit the Related Resources section of this post.

Why the NEXT_PUBLIC prefix and process.env are used with environment variables in Next.js recap

Previously, I had written a post entitled Why being able to use dotenv with Next.js is so huge about using the dotenv npm package with Next.js, and why we add the NEXT_PUBLIC prefix in front of environment variable names. Adding NEXT_PUBLIC, then placing process.env in front of the environment variable name and using it directly in your code will expose it to the browser. You have to add NEXT_PUBLIC to make it happen. Something like the following:

const data = { email, api_key: process.env.NEXT_PUBLIC_CONVERTKIT_API_KEY }

would be exposed to the browser. However, the following:

const API_KEY = process.env.NEXT_PUBLIC_CONVERTKIT_API_KEY const data = { email, api_key: API_KEY }

would not, because it is saved as the value of a variable. And that is the way I have always approached my environment variables, especially when using dotenv.

However, I found out later, that using the dotenv package is redundant with Next.js. It is not necessary to use dotenv in order to be able to extract one’s environment variable values from the .env.local file.

The importance of the env.local file

It is important to note that you have to save your environment variables in your .env.local file. That is where Next.js expects you to keep your secrets.

It is also (most) important to note that you have to add your .env.local file to your .gitignore file immediately upon creation of your project and before committing and pushing any changes to remote. This is both so you don't forget to do so later, and to ensure that your sensitive information stored as the values of your variables are never exposed on Github or wherever else. Next.js' create-next-app does create a .gitignore file for you which includes the .env.local file, but if you are new to all this, it is good practice to double check that the file is there and populated. The .env file is NOT included. .env is meant for non-sensitive, default env var values, and therefore does not need to be included in .gitignore.

Below is what I have in my next.config.js file for my Next Blog which I am in the process of building, and in which I have set up both environment variables for development and production:

const webpack = require('webpack') const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', webpack: (config, { dev, isServer }) => { config.module.rules.push({ test: /\.svg$/, use: ['@svgr/webpack'], }) if (!dev && !isServer) { // Replace React with Preact only in client production build Object.assign(config.resolve.alias, { 'react/jsx-runtime.js': 'preact/compat/jsx-runtime', react: 'preact/compat', 'react-dom/test-utils': 'preact/test-utils', 'react-dom': 'preact/compat', }) } if (isServer) { require('./scripts/generate-sitemap') } if (!isServer) { require('./scripts/compose') } return config }, }) /** @type {import('next').NextConfig} */ const nextConfig = { /* Configure pageExtensions to include md and mdx */ pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx'], /* Optionally, add any other Next.js config below */ reactStrictMode: true, } module.exports = withBundleAnalyzer(nextConfig)

No evidence of env vars. No evidence of dotenv.

Next.js provides us with three different environments

By default, Next.js provides us with 3 different environments. The environments available through Next.js by default are development, production, and test.

The way I can differentiate between and even use both development and production environments locally is to create an .env.development.local file for my env vars (short for environment variables) in development and an .env.production.local file for my env vars in local production. Then I am able to test my production environment/build to avoid unexpected surprises before I push to remote.

Environment variable naming

However, and this is very important, I keep the env var names the same across environments and in the code. Otherwise, only one environment, the one defined in the code using ONE SET of env vars, will work.

Also very important, is that the env var names have to match on vercel.com as well. If I name my env var for my MongoDB database MONGODB_DATABASE in the code, it has to be defined as MONGODB_DATABASE in both the .env.development.local AND .env.production.local files. Just the values are different. These two files are also what I use on my local machine to switch between development and production.

When I run npm run dev, the env vars in .env.development.local are extracted. And when I run npm start AFTER running npm run build to build my application's production code, then tbe env vars in .env.production.local are extracted.

Lastly, I have to add my env vars to my project on vercel.com. There, I also have to name the env var MONGODB_DATABASE, for example, and add the value I want for production there. THEN everything works as expected both on my local machine AND on my remote server.

No need to require and call dotenv as I had done in the past. This was not wrong, but it means one less dependency to include, which is good for application optimization.

Conclusion

The Next.js documentation regarding support for environment variables is pretty good, and if you already have been using environment variables with dotenv in your Node.js projects in the past, it will be fairly easy to follow. I am including reference to the Next.js documentation at the end of the post under Related Resources.