Open-source project
expatfile/next-runtime-env avatar
expatfile/next-runtime-env

next-runtime-env injects NEXT_PUBLIC_ variables after the build

Next.js Runtime Environment Configuration - Populates your environment at runtime rather than build time.

653 stars40 forksTypeScriptMIT

At a glance

What is it?
Expatfile's next-runtime-env adds environment values to a Next.js app at runtime instead of at build time, so one artefact can serve several environments. The cost is a script tag in your layout, a client-side accessor, and a major version chosen by router.
Who is it for?
Adopt next-runtime-env if you ship a single Next.js build to several environments and need NEXT_PUBLIC_ values to change per deployment rather than per build. Do not reach for it when you only have one environment, when your values are server side secrets, or when you are still on a Next.js version older than 12, since the library branches by major version and router there.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 156 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Build once, deploy many, without rebuilding the bundle

The problem next-runtime-env attacks is narrow and very real. Next.js bakes values prefixed with NEXT_PUBLIC_ into the client bundle when it builds, which means the same build artefact carries the same configuration to every environment it reaches. A staging box and a production box then need separate builds, and the build step becomes environment specific. The project frames the fix in the deployment vocabulary it borrows from: build once, deploy many, the phrase it links to continuous delivery and to the twelve-factor methodology. Its own description says it populates the environment at runtime rather than at build time, and the README puts it more bluntly, that the same build can be used across various environments without rebuilds. The audience is therefore teams that containerise or promote a single Next.js artefact between environments and need the public configuration to follow the deployment instead of the build.

PublicEnvScript is a script tag in your document head

The mechanism is visible in the getting started example. You import a component and place it inside the head of your root layout:

js
// app/layout.tsx
import { PublicEnvScript } from 'next-runtime-env';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <PublicEnvScript />
      </head>
      <body>
        {children}
      </body>
    </html>
  );
}

The documentation states that this component automatically exposes all environment variables prefixed with NEXT_PUBLIC_ to the browser, which means the values reach the client at request time through the rendered HTML rather than through the compiled bundle. The cost of that design is that every value it exposes is by definition public. Any variable carrying a secret must keep a name that does not start with NEXT_PUBLIC_, and that rule is enforced by your own naming discipline rather than by the library.

The env() accessor keeps reads out of the build output

Reading a value on the client goes through a helper function rather than the raw process.env object:

tsx
// app/client-page.tsx
'use client';
import { env } from 'next-runtime-env';

export default function SomePage() {
  const NEXT_PUBLIC_FOO = env('NEXT_PUBLIC_FOO');
  return <main>NEXT_PUBLIC_FOO: {NEXT_PUBLIC_FOO}</main>;
}

The component has to be marked as a client component because the value is read in the browser. The project describes itself as isomorphic, working on both server and browser and even in middleware, and the examples folder ships separate variants for the App Router with context, the App Router with script, and the Pages Router, which suggests the delivery mechanism differs by router and by the strategy you choose. Custom variable exposure, where a variable without the NEXT_PUBLIC_ prefix is deliberately published, is handled separately and pointed at the document docs/EXPOSING_CUSTOM_ENV.md, so the default path stays narrow by design.

The major version line is decided by your Next.js router

This is the detail that catches people out, because the library ships parallel major lines and the README maps them to router generations rather than to features of its own. The version guide states that 3.x is Next.js 14 with advanced caching, 2.x is Next.js 13 App Router, and 1.x is Next.js 12 and 13 Page Router. The compatibility notes add the operational advice: for Next.js 14 use [email protected] for optimal caching support, for Next.js 13 opt for [email protected], and for Next.js 12 and 13 Page Router stay on [email protected]. The package manifest in the current branch lists next ^14 and react ^18 as runtime dependencies, consistent with the 3.x line. Getting this wrong is not a soft failure, since a package built for one router generation may not carry the component and context handling another expects.

Releases come from semantic-release, and the branch is development

Maintenance facts here are worth reading carefully rather than assuming. The repository's default branch is development, and the version field in package.json reads 0.0.0-development, which is what a semantic-release setup leaves in the working branch before the pipeline stamps a release. The release script in package.json is semantic-release, and the repository root carries a .releaserc.yaml configuration alongside a scripts/ directory, so versions and changelog entries are produced by tooling rather than by hand. The most recent published tag listed for the project is v3.3.0 on 2025-03-29, with prerelease tags v3.3.0-alpha.6 and v3.3.0-alpha.5 published on the same day. The last push to the repository was on 2026-05-21. That gap between a recent push and a release from the previous year is not a contradiction, but it does mean you should expect to install a published version rather than the newest commit.

Exposing variables that are not prefixed takes a deliberate step

The default surface of the library is the NEXT_PUBLIC_ prefix, and anything beyond that is a documented extra. The README points to docs/MAKING_ENV_PUBLIC.md for the case where you need to expose non-prefixed environment variables to the browser, and to docs/EXPOSING_CUSTOM_ENV.md for custom variable exposure. Both are separate documents rather than options in the snippet above, which tells you the safe default is also the easy default. Note the docs/ directory sits at the repository root next to examples/, so the guidance ships with the package source rather than only on a website. If your deployment needs a value that was not named with the prefix, expect to read both documents before you decide that the library fits, because publishing a non-prefixed variable is precisely the case where an accidental leak would be expensive.

Where next-runtime-env is the wrong tool

There are three cases where this package does not help. The first is a single environment deployment. If you build and deploy to one place, runtime injection buys you nothing and adds a script tag plus a client accessor to every page. The second is server side configuration that must stay private. The mechanism in this package is explicitly about exposing values to the browser, and the presence of a separate document for making non-prefixed variables public is a reminder that the boundary is deliberate. The third is a Next.js version older than 12, since the version guide starts at Next.js 12 and 13 Page Router on the 1.x line. It is also worth noting what the README does not cover. There is no statement about how the injected script behaves under aggressive CDN caching, no documented rollback procedure for a bad release, and no guidance on server component usage beyond the claim that the library works on the server and in middleware. The licence is MIT, held under LICENSE.md at the repository root, which permits use, modification and redistribution in a permissive way, though that is not advice about how the licence interacts with your own product.

Editorial conclusion

Adopt next-runtime-env if you ship a single Next.js build to several environments and need NEXT_PUBLIC_ values to change per deployment rather than per build. Do not reach for it when you only have one environment, when your values are server side secrets, or when you are still on a Next.js version older than 12, since the library branches by major version and router there. Before you install it, confirm that your router matches the 1.x, 2.x or 3.x line, keep every secret out of a NEXT_PUBLIC_ name, and read docs/MAKING_ENV_PUBLIC.md if you need to expose a variable that is not prefixed.

Frequently asked questions

How do I expose environment variables to the browser in next-runtime-env?

Add the PublicEnvScript component inside the head of your app/layout.tsx root layout. The documentation states it automatically exposes all environment variables prefixed with NEXT_PUBLIC_ to the browser.

How do I read an environment variable on the client with next-runtime-env?

Import the env function from next-runtime-env in a component marked with the use client directive and call it with the variable name, for example env('NEXT_PUBLIC_FOO'). The examples folder ships variants for the App Router with context, the App Router with script, and the Pages Router.

Which next-runtime-env version should I install for my Next.js version?

Use [email protected] for Next.js 14, [email protected] for Next.js 13 with the App Router, and [email protected] for Next.js 12 or 13 with the Page Router. The 3.x line is the one described as supporting advanced caching.

How do I expose a variable that does not start with NEXT_PUBLIC_?

The README points to docs/MAKING_ENV_PUBLIC.md for exposing non-prefixed environment variables to the browser, and to docs/EXPOSING_CUSTOM_ENV.md for custom variable exposure. Both documents ship in the docs/ directory of the repository.

Official sources

  1. expatfile/next-runtime-env on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/expatfile-next-runtime-env.svg)](https://hysenlabs.com/projects/expatfile-next-runtime-env)

Was this useful?