Next.js Environment Variables
- Usage is simple, you could directly access the config via
process.env.NEXT_PUBLIC_*
, for example:
// call-site, agents.js
const restaurantApi = axios.createConfig({
baseUrl: process.env.NEXT_PUBLIC_RESTAURANT_API_URI,
});
- When you change any
NEXT_PUBLIC_*
variables, you'd have to (re)build the application and/or deploy the new bundle. - Managing environment variables may be cumbersome when you're following The Twelve Factors.
- How would you manage the environment variables when you have different environment variables in deploys (
development
,staging
,production
, etc)?
- How would you manage the environment variables when you have different environment variables in deploys (
Next.js Runtime Configuration
- De-couple with build-time environment variables, just build once for production bundle.
- You could use the same production bundle with different public runtime configurations in deploys.
- Usage is simple, you could access the config via a helper from
next/config
, for example:
// set up in next.config.js
module.exports = {
publicRuntimeConfig: {
restaurantApi: process.env.RUNTIME_RESTAURANT_API_URI, // Pass through env variables
},
}
// call-site, agents.js
import getConfig from 'next/config';
const restaurantApi = axios.createConfig({
baseUrl: getConfig().publicRuntimeConfig.restaurantApi,
});
- Runtime configuration won't be available to any page (or component in a page) without
getInitialProps
.- It won't work for
Static
andSSG
pages.
- It won't work for
- There is a bug where the
publicRuntimeConfig
is undefined in SSR pages.
- On server-side, the config can be accessed just like ordinary environment variables.
- On client-side, first to retreive the config from the server and then store it in
window
.- Ensure that the config is injected and stored before its being used.
First, let's add a new API route called /api/config
:
// src/pages/api/config.js
const config = {
restaurantApi: process.env.RESTAURANT_API_URI,
};
// properly access public runtime configuration on both client-side and server-side
export const getPublicConfig = (name) =>
typeof window === 'undefined' ? config[name] : window.PUBLIC_CONFIG[name];
export default function handler(_req, res) {
res.status(200).send(`window.PUBLIC_CONFIG = ${JSON.stringify(config)}`);
}
Then, add a script tag in the head, you could add it to either src/pages/_app.tsx
or src/pages/_document.tsx
, if you don't use any of them, you could add it to every pages (src/pages/*.tsx
):
<Head>
<script src="/api/config" defer />
</Head>
Now, you can directly access the config via window.PUBLIC_CONFIG.*
:
import { getPublicConfig } from 'pages/api/config';
// call-site, agents.js
const restaurantApi = axios.createConfig({
baseUrl: getPublicConfig('restaurantApi'),
});
- De-couple with build-time environment variables, just build once for production bundle.
- You could use the same production bundle with different public runtime configurations in deploys.
- It works for
Server
,Static
andSSG
pages as long as the config is present. - Usage is simple, you could access the config via
window.PUBLIC_CONFIG.*
.
window
is polluted on the client-side.- It is confused in combination with Next.js Environment Variables and Next.js Runtime Configuration.
Thank you for the response @jihchi, I was able to achieve this in app router as well with the following changes.
In root
/layout.tsx
:And changing the
content-type
of the api response to beapplication/javascript
.