Skip to content
DMNO
🚧 DMNO is still in beta! Use with caution!
✨ If you've tried DMNO or looked through the docs, let us know what you think!

Next.js

If you have an existing Next.js app, you’re probably already familiar with how environment variables work in Next. Check their docs here if you need a refresher.

Now forget all of that, and let’s simplify things with DMNO. 🥳

Initialize your Next.js integration

Using dmno init we will automatically detect that you are using Next.js and install the necessary packages and configuration for you.

Terminal window
npx dmno init

Skip to Configure… once this is complete.

Manual Setup

If you prefer, you can install dmno itself and the nextjs-integration package manually:

Terminal window
npm add @dmno/nextjs-integration dmno

Then, in your next.config.mjs file, import and add the dmno plugin:

import { dmnoNextConfigPlugin } from '@dmno/nextjs-integration';
/** @type {import('next').NextConfig} */
const nextConfig = {
// your existing config...
};
export default nextConfig;
export default dmnoNextConfigPlugin()(nextConfig);

Configure your environment variables

dmno init will scaffold out the schema in your config.mts files based on your existing .env files. See our Schema Guide for the specifics of how to author additional updates to your DMNO schema.

Injecting config

Unfortunately, NextJS has limited options to reliably inject code into their framework. So, we need to do a little more manual work to get things wired up correctly.

While things may appear to work during development, when you run next build, you’ll likely see some errors about DMNO_CONFIG not existing. To fix this, you need to import a script that will populate it.

import '@dmno/nextjs-integration/inject';

You should do this in a main file that others use, like your main layout:

app/layout.tsx
import '@dmno/nextjs-integration/inject';
export default function RootLayout({ children }) {
// ...

You also need to add this import to any API routes:

app/some-endpoint/route.ts
import '@dmno/nextjs-integration/inject';
export async function GET() {
//...

And sometimes to other helper files that are trying to access config. If you ever see the error when you try to run a build, just add the import and you should be good to go.

Hopefully this will be fixed soon or we can find a better workaround!

Adjusting package.json scripts

Unlike some of our other integrations, the next integration requires that you run your next commands via dmno run, so you must modify your package.json scripts:

package.json
{
"name": "yourapp",
"scripts": {
"dev": "dmno run -w -- next dev",
"build": "dmno run -- next build",
"start": "dmno run -- next start",
"lint": "dmno run -- next lint"
},
// ...
}

Accessing config

Use DMNO_CONFIG and DMNO_PUBLIC_CONFIG instead of process.env 🎉

Security and secrets

While building your site, nextjs does two builds - one for the client and one for the server. During the client build, we only replace references to DMNO_PUBLIC_CONFIG which never contains anything sensitive so you can’t accidentally leak any secrets into the JS of your site. Any references to DMNO_CONFIG in the client code will also throw a helpful error.

However, because NextJS does server-side rendering regardless of if you are doing SSG or SSR or some hybrid, it is still possible to leak secrets in the content of a server-rendered page. In general, try to use DMNO_PUBLIC_CONFIG and be careful about when/how you use secrets.

While it’s not perfect, this should be a bit better than standard env var handling in NextJS - and we are working on some more tooling to help detect and stop leaked secrets - just like we have in our other integrations.

Dynamic public config

If you’d like to be able to alter certain configuration values at boot time and load them in the client rather than relying on values bundled into your code, you need to expose an API endpoint which exposes this public+dynamic config.

See the dynamic config guide for more details.

Unfortunately, NextJS does not let us automatically inject the API route required to expose these config values, so if you want to use this feature, you must manually add an api route:

app/fetch-dynamic-public-config/route.ts
import { publicDynamicEnvObj } from '@dmno/nextjs-integration/inject';
export const dynamic = 'force-dynamic';
export async function GET() {
return Response.json(publicDynamicEnvObj);
}

NOTE - fetching this config makes a blocking http request, so you should think carefully about if and how you use this feature, especially if performance is important your site. See the dynamic config guide for more details.