夯HumGuides
Back to home

SSR, SSG and ISG

Pages default to SSR. Select a mode in the page’s define.config: SSG generates at build time, while ISG can generate missing pages and update expired output. This guide itself is generated during the build.

TypeScript
// routes/posts/[slug].tsx
export const config = define.config({
  render: { mode: "ssg", slugs: ["hello", "getting-started"] },
});

// For request-time generation and updates, replace render with:
// { mode: "isg", revalidate: 60, slugs: ["hello"] }

A parameter-free SSG route is generated automatically. Dynamic SSG routes require a slugs array; an empty array generates no pages. For one parameter, entries may be slug values or full paths. Multiple parameters require full paths such as /en/posts/hello. Invalid, duplicate or shadowed paths fail the build. SSG paths outside the table return 404.

ISG uses the table as an optional pre-generation list. Missing paths generate on their first request. Set fallback: false to restrict the route to its table. revalidate is a positive lifetime in seconds. Concurrent generation requests in one service are combined; a failed update keeps the previous version.

Application setup

TypeScript
import { createPageService, mountHum } from "@humjs/core";
import { config } from "virtual:hum/build";

const pages = createPageService();
await mountHum(app, { ...config, pages });

// A Worker can let its execution context own background regeneration:
// createPageService({
//   background: (task, c) => c.executionCtx.waitUntil(task),
// });

The default service stores generated ISG pages in memory for the life of the process. Pass a store with get(key) andset(key, page) for shared persistence. Writes must atomically publish a complete page; keys include the build ID. Coordination between different server instances belongs to that adapter.

Without a background executor, expired pages update before the response. With one, the response uses the old version while the executor owns the update. Full HTML and Partial responses are published together from the same render, preserving shared signals and island props.

Build and request behavior

Configure hum({ devEntry: "app.ts", prerenderOrigin: "https://example.com" }). The build loads the compiled app module without starting the Node listener. Route configuration is evaluated in Node; build-time handlers must work there without deployment-only bindings. The canonical origin defaults to http://localhost.

Static modes generate public pages with a fresh GET request, without cookies, authorization or query parameters. Application middleware wraps each request; directory middleware and page handlers run during generation. Keep personalized pages and request-specific guards on SSR. Responses with cookies, varying representations, private cache controls or a status other than 200 cannot be generated. Streaming remains an SSR option. Non-GET methods continue through the normal handler chain.

Development always renders fresh output. Production embeds generated pages in the generated Hum build module and serves them through Hono. Standalone builds bundle that module with the server; ordinary builds keep it in the ESM module tree alongside the compiled app. Neither mode discovers page files at runtime. Pure static hosting is not provided by this output format.