feat: add Netlify deployment config for Console frontend#2362
feat: add Netlify deployment config for Console frontend#2362malinskibeniamin wants to merge 7 commits intomasterfrom
Conversation
Add netlify.toml with: - Build config (bun install + rsbuild build) - CORS headers for cross-origin Module Federation loading - Cache-busting for embedded.js and mf-manifest.json - Immutable caching for hashed static assets - SPA fallback redirect for standalone mode This enables Console frontend to be deployed as a static Netlify site, serving the same assets to all clusters. The per-cluster API URL is provided by Cloud UI via the gatewayApiUrl prop at runtime. Companion PRs: - redpanda-data/cloudv2#25386 (Console Netlify support in Cloud UI) - #2361 (MF v2 search params fix) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
@claude review |
|
Claude finished @malinskibeniamin's task in 1m 9s —— View job Code Review
Overall this is a clean, minimal config. A few things worth considering:
|
- Move CORS headers from /* to specific MF entry points only (embedded.js, mf-manifest.json, static/*) - Add Access-Control-Max-Age for preflight caching - Add comment explaining NODE_OPTIONS heap ceiling Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
@claude review |
|
Claude finished @malinskibeniamin's task in 1m 17s —— View job Code Review
|
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
@claude review |
|
Claude finished @malinskibeniamin's task in 57s —— View job Code Review
All previous feedback has been addressed. This is in good shape. A few remaining observations:
|
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…igate TanStack Router expects search params via the search option, not embedded in the to string. Split on ? and pass separately for forward compatibility with future TanStack Router versions. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
@claude review |
|
Claude finished @malinskibeniamin's task in 1m 9s —— View job Code Review
All previous feedback has been fully addressed. This is in good shape. One observation on the new
|
split('?') would silently discard params after a second '?' in
malformed paths. indexOf correctly handles the first '?' only.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
| for = "/static/*" | ||
| [headers.values] | ||
| Cache-Control = "public, max-age=31536000, immutable" | ||
| Access-Control-Allow-Origin = "*" |
There was a problem hiding this comment.
Is this how we manage it normally, could we enable CORS only for the specific domains ?
There was a problem hiding this comment.
Good question. For Module Federation, the host app (Cloud UI on cloud.redpanda.com) loads remoteEntry.js and chunk files from this Netlify site via <script> tags and fetch(). Using Access-Control-Allow-Origin: * is standard for public static assets (same pattern as any CDN-served JS library).
We could restrict to specific domains (e.g., *.redpanda.com, *.netlify.app), but:
- These are public, non-sensitive static JS/CSS files with no auth
- Host app Netlify site uses the same
Access-Control-Allow-Origin: *pattern for external scripts
The wildcard is scoped to only the MF entry points (/embedded.js, /mf-manifest.json, /static/*), not all responses. The catch-all /* block only has X-Content-Type-Options: nosniff without CORS. So the exposure is limited to files that are designed to be publicly fetchable.
frontend/netlify.toml
Outdated
| base = "frontend" | ||
| # NODE_OPTIONS: 16 GB is a V8 heap ceiling guard, not actual memory usage. | ||
| # It prevents OOM kills during large builds; real RSS stays well below this. | ||
| command = "bun install && NODE_OPTIONS=--max_old_space_size=16384 bun run build" |
There was a problem hiding this comment.
Are we charged by memory consumption in builds? having a high node old space size could be hiding some bugs.
There was a problem hiding this comment.
Good catch. The --max_old_space_size=16384 is a V8 heap ceiling, not actual memory allocation — it just raises the limit before V8 triggers an OOM. The actual RSS during a Console build is typically 2-4 GB.
Netlify doesn't charge by memory consumption — builds run on shared VMs with a fixed time limit. The risk of a high ceiling is exactly what you said: it could mask a memory leak in the bundler that would otherwise surface as an OOM.
That said, other app's Netlify build uses NODE_OPTIONS=--max_old_space_size=4096 (see netlify.toml). We could lower this to 4096 or 8192 to be more conservative while still avoiding legitimate OOM during large builds.
There was a problem hiding this comment.
Lowered to 4096 in 286d804 to match Cloud UI's pattern.
Align with Cloud UI's netlify.toml. 16 GB was unnecessarily high and could mask bundler memory leaks. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

Summary
Add Netlify deployment configuration for Console frontend, enabling it to be deployed as a static site alongside the existing Go HTTP server deployment.
What's included
frontend/netlify.toml— Build config, CORS headers for cross-origin MF loading, cache controlfrontend/public/_redirects— SPA fallback for standalone modeHow it works
Console frontend assets can now be deployed to a Netlify site (e.g.,
redpanda-console-ui). Cloud UI loads the assets from Netlify whenREACT_APP_CONSOLE_FRONTEND_URLis set, with automatic fallback to the cluster's Go HTTP server when Netlify is unreachable.Deployment modes
REACT_APP_CONSOLE_FRONTEND_URL/mf-manifest.jsoncluster.redpandaConsole.url/embedded.jsREACT_APP_CONSOLE_FRONTEND_URL_OVERRIDE/embedded.jsFallback chain (implemented in Cloud UI)
Prerequisites
enable-console-mf-v2feature flag enabled in LaunchDarklyTest plan
bun run buildproduces correct output inbuild/(embedded.js, mf-manifest.json, static assets)embedded.jsandmf-manifest.json_redirectsSPA fallback works for standalone navigation🤖 Generated with Claude Code