# Rendering on the server — Mercury LMS > HS4 of Mercury Hyperscript. `@fiberfx/hyperscript/server` renders components to an HTML string with no effects run; `hydrate` / `hydrateRoot` adopt that HTML in the browser. `@fiberfx/render-to-string` 4.0.0 re-exports the same module. ## Read this when You render a page or an island to HTML on a server or in a test, or you attach components to server-rendered markup in the browser. ## The contract - `renderToString(vnode, context?): string`. The default export, `render` and `renderToStaticMarkup` are the same function. `context` is the root's initial legacy context object (for `getChildContext`); `createContext` code omits it. - While rendering to a string, `useEffect` and `useLayoutEffect` callbacks never run, and event handlers are not serialized. `useState` gives its initial value; `useContext` reads providers in the tree. - `useId`: ids are in tree order (`P0-0`, `P0-1`, …), reset per `renderToString` root, and match after hydration. - A component that throws a promise makes `renderToString` throw `Error('Use "renderToStringAsync" for suspenseful rendering.')`. - `renderToStringAsync(vnode, context?)`: always `await` it. It re-renders a suspended component after its promise settles, wraps that output in `…`, and follows at most 25 nested levels. Preview: no test covers it. - Browser: `hydrate(vnode, parent)` from `@fiberfx/hyperscript`, or `hydrateRoot(container, children)` from `@fiberfx/hyperscript/client`, which returns `{ render, unmount }`. Hydrate the same tree with the same props; the server's nodes are kept. - `useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)`: `getServerSnapshot` is read on the server and during hydration; after hydration it re-renders with `getSnapshot`. It subscribes in an effect. ## Minimal example ```tsx // server import { renderToString } from "@fiberfx/hyperscript/server"; const html = renderToString(); // "" // browser import { hydrateRoot } from "@fiberfx/hyperscript/client"; const app = document.getElementById("app"); if (app) hydrateRoot(app, ); ``` ## Never emit - `window`, `document` or `navigator` read during render in a component that renders on the server: read them in `useEffect`, or through `useSyncExternalStore` with a `getServerSnapshot`. - `renderToStringAsync` without `await`. - `./jsx`, `./stream` or `./stream-node` subpaths of `@fiberfx/render-to-string`: they are not exported. ## Next - Context, portals and memo: /hyperscript/context/llms.txt - Testing and inspecting: /hyperscript/testing/llms.txt - This companion: /hyperscript/server/llms.txt (the page as Markdown, `/hyperscript/server.md`, is planned for W3) ## Navigation - [Read this page in the browser](/hyperscript/server) - [Agent index](/llms.txt) - [All English companions](/llms-full.txt) - [Sitemap](/sitemap.xml) - [Course companion](/hyperscript/llms.txt)