Skip to content

RFC: Backend Rendering of Swagger UI during Next.js Build Phase (Production Container)

Julia edited this page Jul 1, 2025 · 1 revision

Context

Currently, the Swagger UI is rendered on the frontend as a Single Page Application (SPA) using React components. The Swagger schema is fetched and patched dynamically during development and runtime.

Our production build is based on a multi-stage Docker setup that:

  • Fetches and patches the Swagger schema via scripts (fetchSwaggerSchema.mjs, patchSwaggerServer.mjs)
  • Runs next build and next export to produce a static site
  • Serves static assets from the /out directory

However, the Swagger UI is still rendered dynamically in the browser. This does not align with the static site generation (SSG) model and results in a heavier client bundle and delayed content rendering.

Requirement

Render the Swagger on the Next.js build phase, replacing the current dynamic SPA-based approach. This should be applied to the production container only.

Proposal

Introduce a backend-rendered Swagger UI by generating a fully static HTML page during the production Docker build process. This static page will embed the Swagger schema and replace the current React-based dynamic Swagger component.

Steps

  1. Update the Dockerfile build stage to:

    • Run the existing scripts:
      node scripts/fetchSwaggerSchema.mjs && node scripts/patchSwaggerServer.mjs
    • Add a new step to generate a static Swagger HTML page from the patched schema using swagger-ui-dist or a similar tool.
    • Place the generated swagger.html into the /public directory (or directly into /out after export).
    • Proceed with:
      npx next build && npx next export
  2. Update routing or links on the frontend to reference /swagger.html instead of rendering <SwaggerUI /> dynamically.


Environment-Based Rendering Tip

To ensure compatibility with both development (SPA-based Swagger) and production (static HTML), we recommend introducing a conditional switch in the Swagger component.

Add a public environment variable:

# In .env.production
NEXT_PUBLIC_STATIC_SWAGGER=true

# In .env.development
NEXT_PUBLIC_STATIC_SWAGGER=false

Update the Swagger component logic:

if (process.env.NEXT_PUBLIC_STATIC_SWAGGER === 'true') {
  if (typeof window !== 'undefined') {
    window.location.href = '/swagger.html';
  }
  return null;
}

This allows:

  • The dev container to continue using dynamic Swagger UI with hot reloading (this can be changed if needed).

  • The prod container to redirect to a statically pre-generated Swagger page.

Tools

  • swagger-ui-dist: For generating a self-contained Swagger UI HTML page.

  • Node.js script (e.g., generateSwaggerStaticUI.js) to combine the patched schema with a Swagger UI template.

Benefits

  • Swagger documentation is available immediately as static content.

  • Reduces frontend JavaScript bundle size.

  • Fully compatible with SSG and CDN caching strategies.

  • No runtime fetch or React rendering required for API docs.

Risks / Limitations

  • Swagger documentation becomes static — schema updates require a new build.

  • Any runtime customization must be shifted to build-time.

Next Steps

  • Create generateSwaggerStaticUI.js script
  • Update the Dockerfile build stage
  • Update Next.js links/routes to point to the static Swagger page
  • Update Swagger React component for both environments – development and production
  • (Optional) Add a CI step to validate the presence of /swagger.html in the exported output

Clone this wiki locally