2024/05/09
(This guide uses the app router version of Next.js but some of it may still be applicable to the page router version)
Using environment variables in Next.js can be very confusing. Searching around the web it doesn't feel like anyone is solving the issue of "how do I get env variables into a Next.js container?". That is why I created this guide, to explain how this can be done. This guide is also complimented by an example repo which can be found here.
Environment variables can be supplied to Next.js in multiple ways. How they are supplied and how your Next.js application is set up has a big impact on what is possible.
When reading through the documentation it seems like using the .env
files are the way to go. These files, depending on their name make variables accessible through the field process.env.{variable name}
. The .env
files you would usually create are:
.env.local
- The contents in this file is accessible no matter what your Next.js environment is..env.development
- The contents in this file are only accessible when running in dev mode npm run dev
..env.production
- The contents in this file are only accessible when using a production image.Environment variables that are present on your system or in the container of the Next.js app are also available. These can also be accessed through the process.env.{variable name}
field. However, since most Next.js pages are statically generated, these values won't change even if you give the container new and different variables. There is a way to circumvent this which I will explain in the next section.
"If both .env
files and provided environment variables don't work because of being statically generated, how am I supposed to provide new values?"
Great question. There are multiple ways to use provided environment variables instead of the baked in ones.
unstable_noStore()
which is described here, makes it so the component is rendered server-side when requested and will therefore use the current environment variables. Simply call it in your component like so and it should work:
_10import { unstable_noStore } from "next/dist/server/web/spec-extension/unstable-no-store";_10_10function Component() {_10 unstable_noStore();_10_10 return(_10 <p>{process.env.providedValue}</p>_10 )_10}
This method is prepended with unstable_
because there is a high chance it may change in a future release of Next.js.
A server action is run on the server when requested. Meaning it will use the environment variables currently defined. Define an action in the src/actions
folder like this:
_15'use server'_15_15interface EnvVariableResult {_15 theVariable: string | undefined_15}_15_15async function EnvVariable(): Promise<EnvVariableResult> {_15 'use server';_15_15 return {_15 theVariable: process.env.actionVariable || undefined_15 }_15}_15_15export default EnvVariable;
This defines a simple server action that can be called from another component. The function must be async to be a server action. This variable can then be used in a client component like this:
_22'use client';_22_22import React, {useEffect, useState} from 'react';_22import EnvVariable from "@/actions/test";_22_22function ClientComponent() {_22 const [theVariable, setTheVariable] = useState<string | undefined>(undefined);_22_22 useEffect(() => {_22 EnvVariable().then(result => {_22 setTheVariable(result.theVariable);_22 });_22 }, [])_22_22 if (theVariable) {_22 return (_22 <p>{theVariable}</p>_22 )_22 }_22}_22_22export default ClientComponent;
This should render the environment variable. Calling this from a normal server-side component that isn't using unstable_noStore()
will not result in anything, as that component was rendered at compile-time.
The example doesn't return anything til theVariable
is set because it won't be ready when initially rendered.
To avoid using useEffect
I would definitely go with using unstable_noStore()
server side. This is the simplest approach and makes it so you won't have to use 'use client'
when not necessary. To still use environment variables in a client component I would recommend passing them in from a parent server component, this way you avoid the async complexity of having to use the server side action.
I have created an example project which can be found here. It shows how rendering with unstable_noStore()
and without impacts environment variables. The readme goes into detail with this, so you don't have to run the project yourself.
Congrats! You should now know how to handle environment variables in Next.js. I hope this was able to help you 😊.