Front-End Web Deep Dive: Runtime Config
- Last Updated: October 15, 2026
Heroku introduced the Twelve-Factor App philosophy in 2009 for building modern, scalable, and maintainable cloud-native applications. One of its core tenets is Config:
An app’s config is everything that is likely to vary between deploys (staging, production, developer environments, etc).
While this is a solved problem for the server-side, it remains a challenge for the front-end. Most static web apps have configuration, such as environment variables accessed via process.env, compiled directly into their build artifacts. Because these values are “baked in” during the build, a full re-build is required just to change an API URL when an app is promoted from staging to production.
Ten years ago, we published create-react-app-buildpack to solve this problem on Heroku for apps developed with the create-react-app tool. This buildpack performed a lot of magic to inject REACT_ environment variables into the JavaScript bundle at runtime. Despite its popularity (with over 3.2K stars on Github), we never succeeded in generalizing the architecture because of the security risks involved in altering the final JavaScript bundle.
We have evolved that approach. Runtime configuration has been brought to the Front-End Web Cloud Native Buildpack in a way that is standard, secure, and requires zero re-builds. By revisiting Twelve-Factor principles through the lens of modern web standards, we have created a strategy that works for any framework.
Env as HTML data
With the Heroku Front-End Web CNB, runtime configuration is managed through a web-standard approach: writing environment variables directly into the HTML document as data-* attributes. This method avoids the pitfalls of bundle-injections by treating the HTML entry point as the configuration source of truth.
How it works
To get started, set your runtime configuration of your static web app using the PUBLIC_WEB_ prefix. For example:
PUBLIC_WEB_API_URL=https://api-staging.example.comThen, whenever the included static web server starts-up, whether using
docker run or Heroku deployment, these variables will be written into the static HTML document <head> element as data-* attributes.
<html>
<head data-public_web_api_url="https://api-staging.example.com">
<title>Example</title>
</head>
<body>
<h1>Example</h1>
</body>
</html>
You can even include default values for these attributes in your source document, and they will be overwritten at runtime by values set in the environment.
These attribute values are accessible directly within the JavaScript app via document.head.dataset.
<html>
<head data-public_web_api_url="https://api-staging.example.com">
<title>Example</title>
<script>
const response = await fetch(document.head.dataset.public_web_api_url, {
method: "POST",
// …
});
</script>
</head>
<body>
<h1>Example</h1>
</body>
</html>
Every time the static web server starts, the current PUBLIC_WEB_ configuration is loaded into the app. This supports instant environment variable changes without rebuilding.
For more about using runtime configuration, see the Dev Center article.
Universal compatibility and security
This Env-as-HTML-Data technique is universally compatible. It injects runtime configuration into browser apps as safe, standard, HTML data-* attributes without any framework or platform bias. Because the configuration is part of the HTML document itself, there is no conflict with Content-Security-Policy (CSP), Subresource Integrity (SRI), or other browser safeguards.
Adapting a pre-existing app to this new runtime configuration strategy may require refactoring how its environment values are read to avoid capturing them at build-time.
Crafted from experience
At Heroku, our own front-end engineering team is adopting the Front-End Web Cloud Native Buildpack (CNB) to deliver customer-facing interfaces like dashboard.heroku.com. We’d love to hear your feedback and ideas in the Front-end Web Cloud Native Buildpack’s GitHub issues.
- Originally Published:
- Cloud Native BuildpacksFront End