Sebastian Gomez
Plugins in Next.js
The next.config.js file gives us the ability to do some very powerful things. Because the config file follows a convention, rules every Next.js project shares, it's easy to inject code written by others, which is exactly what we'll call Plugins.
Valid as of Next.js 16: The concept of composing your configuration in next.config.js is still fully valid, next.config.js can export either an object or a function that receives and returns the config. What changed since 2022 are the specific packages: several that were common back then are now unmaintained. Throughout this post I point you to the modern alternative in each case.
Making our app available offline
Historically, to make an app work offline you'd use the next-offline plugin, wrapping your configuration like this:
// Legacy pattern: 'next-offline' is no longer maintained.
const withOffline = require('next-offline');
const config = {
// Whatever goes in your configuration
};
module.exports = withOffline(config);`next-offline` is deprecated. It hasn't been maintained for years and predates the App Router. For PWA / service workers on Next.js 16, use `next-pwa` (Pages Router) or Serwist / your own service worker (App Router). The "wrap the config" pattern above is what matters to learn here; only the package changes.
Composing multiple plugins
Most plugins follow the `withPluginName` convention: they take your Next.js config, wrap it, and return it in the expected format. That lets you apply a composition pattern when you want to use several plugins at once.
It used to be common to reach for a package like next-compose-plugins for this. Today that package is archived too, and the good news is you no longer need it: since each plugin is just a function, you can compose them by hand.
// Manual composition — no extra dependencies (recommended on Next.js 16)
const withOffline = require('next-offline');
const withReactSvg = require('next-react-svg');
const config = {
env: {
MY_ENV: process.env.MY_ENV,
},
};
// Each plugin is a (config) => config function, so just nest them:
module.exports = withOffline(
withReactSvg({
...config,
// next-react-svg specific configuration
}),
);If you have many plugins and prefer something more readable, you can compose them with a reduce:
// reduce alternative — equivalent, no dependencies
const plugins = [withReactSvg, withOffline];
module.exports = plugins.reduce((acc, plugin) => plugin(acc), config);As you can see, chaining plugins in Next.js is still wonderfully natural, and now with one less dependency.
Handling environment variables with .env
Here's a big simplification compared to 2022. You no longer need any plugin (next-env, dotenv-load, etc.) to read environment variables: Next.js automatically loads .env files as of version 9.4. You just create the file.
Create a .env.local at the root of your project and add your variables:
# .env.local
NEXT_PUBLIC_APP_URL=https://www.sebastian-gomez.comImportant tip: Variables you want to use in the browser must be prefixed with NEXT_PUBLIC_. Without that prefix, the variable only exists on the server and arrives as undefined on the client. Also, keep your secrets out of version control: never commit your .env.local to GitHub.
Now, to use the variable in any page or component, just read process.env:
// The variable is prefixed with NEXT_PUBLIC_ so it's available on the client
<a
className="text-pink-600 cursor-pointer hover:underline"
href={process.env.NEXT_PUBLIC_APP_URL}
>
Go to the app
</a>Conclusions
- Plugins are a simple, powerful way to extend Next.js, and the
next.config.jscomposition pattern is still valid on Next.js 16. - The `withPluginName` convention makes it easy and natural to chain multiple plugins, and today you can compose them by hand, with no extra packages.
- For environment variables you no longer need any plugin: use the built in
.envsupport, and remember theNEXT_PUBLIC_prefix to safely expose them to the browser.
Suggested exercises
- Create a basic Next.js 16 project and integrate a plugin of your choice (for example
next-pwa). Read its docs and configure it correctly. - Add two different plugins to your project and compose them by hand (nesting functions or with
reduce), making sure they work together. - Create a
.env.localfile with at least three variables; expose one to the client withNEXT_PUBLIC_and verify the others only exist on the server.
3-point summary
- Next.js plugins make it easy to inject extra functionality following the
withPluginNameconvention. - You can combine multiple plugins with manual function composition, you no longer need
with-compose-plugins(it's archived). - Environment variables are handled with built in
.envsupport; useNEXT_PUBLIC_for the ones you need in the browser.
I hope this post is useful to you and that you can apply it to a project you have in mind, or that it simply helped you understand how plugins work and how to improve the configuration of your Next.js projects.
Leave me a comment if it helped, if you want to add an opinion, or if you have any questions. And remember, if you liked it, you can also share it using the social links below.
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.