Frontend
Rendering: CSR, SSR, SSG
CSR, SSR and SSG are not three ways to write your app. They are three ways to resolve the same pages. You pick one in configuration (and, for SSR, by which adapters you stack); the pages you wrote stay identical.
#Choosing a strategy
export default defineConfig({
rendering: 'ssg' // 'csr' | 'ssr' | 'ssg'
})| Strategy | Type | Description |
|---|---|---|
| csr | client | A pure SPA, rendered in the browser. Ship the Browser adapter. |
| ssr | server + client | Rendered per request on a server/edge adapter, then hydrated in the browser. |
| ssg | build + client | Pre-rendered to static HTML at build (list the routes), then hydrated on load. |
#SSR is a superposition
There is no "SSR mode" to write for. Stack a server (or edge) adapter with the Browser adapter: the server context resolves the first paint, the browser context resolves everything after. The pages never know which one ran them.
import { StoneApp } from '@stone-js/core'
import { Routing } from '@stone-js/router'
import { UseReact } from '@stone-js/use-react'
import { Browser } from '@stone-js/browser-adapter'
import { NodeHttp } from '@stone-js/node-http-adapter'
@Browser() // resolves the interactive app in the browser
@NodeHttp() // ...and the first paint on the server
@UseReact()
@Routing()
@StoneApp({ name: 'tasks-ui' })
export class Application {}import { defineStoneApp } from '@stone-js/core'
import { routerBlueprint } from '@stone-js/router'
import { useReactBlueprint } from '@stone-js/use-react'
import { browserAdapterBlueprint } from '@stone-js/browser-adapter'
import { nodeHttpAdapterBlueprint } from '@stone-js/node-http-adapter'
export const App = defineStoneApp(
{ name: 'tasks-ui' },
[routerBlueprint, useReactBlueprint, browserAdapterBlueprint, nodeHttpAdapterBlueprint]
)#SSG routes
Static generation pre-renders the routes you list. Parameterised routes are listed explicitly. Everything hydrates on load, so the page is interactive after the first paint.
export default defineConfig({
rendering: 'ssg',
ssg: { routes: ['/', '/tasks', '/tasks/1', '/about'] }
})#SOR: server-only, zero client JS
There is a fourth option the superposition model gives you almost for free. Render on a server or edge adapter but do not stack the Browser adapter: the server produces the HTML and there is nothing to hydrate, so no client bundle ships at all. This is Server-Only Rendering (SOR), the zero-JavaScript mode for content that does not need interactivity, a marketing page, a document, an email view.
| Mode | Type | Description |
|---|---|---|
| SSR (hydrated) | server + Browser | Server render, then the browser hydrates: interactive. |
| SOR (server-only) | server, no Browser | Server render, no client bundle, no hydration: zero JS. |
#Streaming SSR
For large pages, the server can stream HTML as it renders instead of buffering the whole document, so the browser starts painting sooner. Streaming is a render option on the server adapter; the pages you wrote do not change.
#Hydration and the snapshot
On SSR and SSG, the server render serialises the page's data into the HTML as a snapshot; the browser hydrates from it instead of re-fetching, so the first interaction is instant and the loader does not run twice. This is automatic; you write pages, not hydration code.