Unlocking Multiple Build Environments in Next.js
Satya Ranjan Sharma
Front-End Developer | Aspiring Full-Stack Engineer | React/Next.js & TypeScript Specialist | Passionate About Scalable Web Applications
Next.js is a robust framework for creating front-end applications. Nonetheless, support for multiple-build environments is one of its main drawbacks.
Next.js build environments are powered by environment variables, which allow us to configure various settings without hardcoding them. This is particularly helpful for activities like maintaining distinct APIs for development, staging, and production or configuring multiple API endpoints depending on the build type. Next.js uses .env files to differentiate development builds from production builds, which simplifies but also limits configuration.
Why It Matters
Environment variables are essential for configuring settings without hardcoding, especially when dealing with different API endpoints for different stages of your application. Yet, the limitation of just two build environments can create challenges for teams looking to streamline their workflows across multiple deployment scenarios.
Next.js environment loading script
The first step to configuring environment variables is to understand how environment variables can be loaded. It turns out that Next.js has a built-in way to set environment variables at build time through the next.config.js file. Specifically, if a property called env is exported, all of the keys specified will be available in the build as environment variables. This is similar (but not identical) to2 how environment variables are loaded from a .env.development or .env.production file. For example, if we wanted to configure an API_ENDPOINT environment variable, it might look something like the following:
// next.config.js
module.exports = {
env: {
API_ENDPOINT: 'https://localhost:1234'
}
};
// src/get-weather.ts
export function getWeather() {
return fetch(`${process.env.API_ENDPOINT}/weather`);
}
Now, if we wanted a different value API_ENDPOINT based on something like the target environment, we could modify our next.config.js script to include this behavior:
领英推荐
// next.config.js
function getAPIEndpoint() {
if (process.env.TARGET_ENVIRONMENT === 'production') {
return 'https://api.example.com';
}
if (process.env.TARGET_ENVIRONMENT === 'staging') {
return 'https://api.staging.example.com';
}
return 'https://localhost:1234'
}
module.exports = {
env: {
API_ENDPOINT: getAPIEndpoint()
}
};
The above example is a good illustration of how we might set different environment variable values based on the environment, but the syntax is a bit verbose and cumbersome. We can improve on this by mimicking the existing environment variable patterns. We would do this by:
The result will look something like this:
.
├── env
│?? ├── .env.demo
│?? ├── .env.development
│?? ├── .env.production
│?? └── .env.staging
├── src
│ └── ...
│
├── next.config.js
└── package.json
// next.config.js
const dotenv = require('dotenv');
const fs = require('fs');
const path = require('path');
function loadTargetEnv(target) {
// Constructs a path such as env/.env.development
const envPath = path.join(__dirname, 'env', `.env.${target}`);
return dotenv.parse(fs.readFileSync(envPath));
}
module.exports = {
env: loadTargetEnv(process.env.TARGET_ENVIRONMENT)
};
Conclusion
While Next.js doesn’t provide default support for multiple environments, it’s possible to emulate the exact desired behavior by leveraging its configurable build process. Here, we’ve outlined a very basic script to load environment variables, but this process can be as customizable as your application needs!