How to Fix: How to set dynamic assetPrefix with __next_set_public_path__
Dynamic assetPrefix fails here because __next_set_public_path__ is not a supported runtime API for changing how Next.js resolves its build assets in the way Webpack Module Federation examples often do. In Next.js, the URLs for /_next/static/… assets are determined from the framework’s own build/runtime pipeline, and assetPrefix is expected to be known early enough to shape those asset URLs consistently. If you try to inject a public path too late, the browser still requests chunks, CSS, and other runtime files from the original location.
Understanding the Root Cause
The core issue is a mismatch between how Next.js computes asset locations and how Webpack publicPath can be changed in other setups. In a plain Webpack application, runtime helpers can sometimes update the chunk loading base path after the page starts. But in Next.js, several layers depend on a stable asset base:
- Build manifests generated at build time reference files under the /_next/ namespace.
- The client runtime loads JavaScript and CSS chunks using values derived from Next.js configuration and server context.
- assetPrefix is a framework-level setting, not just a late-bound Webpack variable.
- Server-rendered HTML may already contain preload or script references pointing to a specific asset origin.
That is why using __next_set_public_path__ to dynamically change the prefix without a rebuild usually does not work reliably. Even if one script path changes, other generated URLs may still point to the old location, causing 404 errors, broken hydration, or missing CSS/chunks.
In practice, if your goal is to serve the same build from different domains or CDNs, you need a solution that aligns with the way Next.js expects asset URLs to be provided:
- Set assetPrefix from an environment variable available when the server starts.
- Use a reverse proxy or CDN that preserves the same /_next/ path externally.
- Deploy separate builds when prefixes truly differ in ways that cannot be abstracted by infrastructure.
Step-by-Step Solution
The safest fix is to stop relying on __next_set_public_path__ for Next.js asset loading and instead provide the prefix through supported configuration.
1. Configure assetPrefix from an environment variable
Update your next.config.mjs so the prefix is resolved from the runtime environment used to start the Next.js server.
const isProd = process.env.NODE_ENV === 'production'
const nextConfig = {
assetPrefix: isProd ? (process.env.NEXT_ASSET_PREFIX || '') : '',
}
export default nextConfig
This lets you start the same application code with a different prefix value per environment, as long as the deployment model supports it.
2. Start the app with the correct prefix
Set the environment variable before starting your server.
NEXT_ASSET_PREFIX=https://cdn.example.com npm start
If you need different environments, use your hosting platform’s environment variable settings rather than patching the client runtime afterward.
3. Keep the CDN or proxy path aligned with /_next/
Your CDN or reverse proxy must correctly serve all generated Next.js assets from the prefixed location.
https://cdn.example.com/_next/static/...
If those files are not available there, chunk loading will fail regardless of configuration.
4. Use rewrites or a reverse proxy when you need one build behind many domains
If the real requirement is “no rebuild, many hostnames,” the better pattern is often to keep assetPrefix stable and let infrastructure map requests correctly.
For example:
- Serve the app from multiple domains.
- Route all /_next/static/ requests through a shared CDN hostname.
- Or proxy each domain’s /_next/ path to the same asset store.
This avoids runtime mutation of paths that Next.js already baked into the page lifecycle.
5. Do not depend on __next_set_public_path__ for Next.js chunk resolution
If your code currently includes something like this:
window.__next_set_public_path__('https://cdn.example.com/_next/')
remove that approach for assetPrefix management. It is not the supported control point for Next.js asset delivery.
6. Validate in production mode
Many asset issues do not appear in development because the dev server behaves differently. Always test using a production build:
npm run build
NEXT_ASSET_PREFIX=https://cdn.example.com npm start
Then verify that:
- Script tags point to the expected prefixed location.
- Chunk files load successfully.
- CSS and images under the Next.js asset pipeline resolve correctly.
Example complete configuration
const nextConfig = {
assetPrefix: process.env.NEXT_ASSET_PREFIX || '',
poweredByHeader: false,
}
export default nextConfig
If you also need app-level access to the value, expose a separate public variable:
const nextConfig = {
assetPrefix: process.env.NEXT_ASSET_PREFIX || '',
env: {
NEXT_PUBLIC_ASSET_PREFIX: process.env.NEXT_ASSET_PREFIX || '',
},
}
export default nextConfig
Use that public variable only for your own URLs. Let Next.js manage its internal asset loading through assetPrefix.
Common Edge Cases
- Static export vs server deployment: If you use export-oriented workflows, asset paths can be even more sensitive. Make sure the exported files and the final hosting path match exactly.
- basePath confusion: basePath and assetPrefix are different. Use basePath when the app lives under a subpath such as /docs. Use assetPrefix for asset hosting, often via CDN.
- Images not loading: next/image has its own constraints depending on loader and remote patterns. Fixing assetPrefix does not automatically solve image domain configuration.
- Only some chunks fail: This usually means the main HTML loaded from one origin but lazy-loaded chunks are being requested from another incorrect origin.
- Hydration errors after path changes: If server-rendered asset references and client runtime asset references disagree, the page may partially render and then fail during hydration.
- Environment variable timing: If your platform injects variables only at build time, changing them at container start may not affect a fully static deployment the way you expect.
FAQ
Can I change assetPrefix in the browser after the app has already loaded?
Not reliably for Next.js internals. By that point, the framework may already have emitted script, preload, and chunk references. assetPrefix should be treated as an early configuration value, not a late client-side toggle.
Is __next_set_public_path__ officially supported for this use case?
No. It is not the recommended mechanism for dynamically controlling Next.js asset URLs across deployments. Prefer assetPrefix, a CDN, or reverse-proxy routing.
How do I avoid rebuilding for every domain?
The usual solution is infrastructure, not client runtime mutation: use a shared CDN hostname, proxy /_next/ requests, or keep the asset origin stable while serving HTML from multiple domains. If the asset origin truly must differ per deployment, supply assetPrefix via environment-backed server startup configuration.
For related implementation details, review the official Next.js assetPrefix documentation and compare it with your hosting/CDN behavior rather than trying to force a Webpack-only runtime pattern into the Next.js asset pipeline.