Rendering Lit components on the server improves initial load performance and SEO. This lesson introduces @lit-labs/ssr and how server rendering and client-side hydration work together.
Why Server-Side Render a Web Component
Without server-side rendering, a Lit component renders nothing until its JavaScript module loads, parses, and runs in the browser — meaning a user (or a search engine crawler) briefly sees empty or missing content. Server-side rendering (SSR) produces the actual HTML markup, including a serialized representation of Shadow DOM, on the server ahead of time, so meaningful content is present immediately in the initial HTML response.
@lit-labs/ssr is Lit's official package for this: it runs your component's render() logic in a Node.js environment (without needing a real browser or DOM), producing HTML output including <template shadowrootmode="open"> elements — a relatively new, standardized way to declare Shadow DOM directly in server-rendered HTML.
// server.js (simplified)
import { render } from '@lit-labs/ssr/lib/render-with-global-dom-shim.js';
import { html } from 'lit';
import './my-greeting.js'; // registers <my-greeting>
const result = render(html`<my-greeting name="Ada"></my-greeting>`);
let htmlString = '';
for (const chunk of result) htmlString += chunk;
// htmlString now contains real markup, including a declarative shadow root
The server never opens a real browser — @lit-labs/ssr implements enough of the DOM/Custom Elements APIs in plain Node.js to run your component's rendering logic directly.
<template shadowrootmode="open"> is a standardized HTML feature that browsers use to attach a shadow root immediately during initial HTML parsing, before any JavaScript runs.
This means the server-rendered markup is visually correct on first paint, even before the component's client-side JavaScript has loaded.
Once the client-side Lit module loads, the component 'hydrates' — Lit recognizes the existing declarative shadow root and attaches its reactive behavior to it, rather than re-rendering from scratch.
Not every browser supports declarative shadow DOM natively in all contexts; @lit-labs/ssr-client's hydration support handles the client-side reconnection either way.
SSR Concepts Cheat Sheet
Key vocabulary for Lit server-side rendering.
Term
Meaning
@lit-labs/ssr
Runs Lit component rendering logic in Node.js
Declarative Shadow DOM
<template shadowrootmode> — Shadow DOM expressed directly in HTML
Hydration
Client-side JS attaching reactivity to existing server-rendered markup
@lit-labs/ssr-client
Client-side helpers supporting hydration
Full framework integration
Meta-frameworks like Astro or custom Node servers using @lit-labs/ssr directly
Current Limitations to Know About
@lit-labs/ssr is officially labeled experimental/labs, meaning its API can still change, and not every Lit feature has full SSR support (some browser-only APIs used inside a component's lifecycle need care to avoid errors when running in Node.js, where window/document behave differently or need shims).
Avoid directly accessing browser-only globals (window.innerWidth, localStorage) inside render() without guarding for a server environment.
Test SSR output for any component before relying on it in production — labs packages can have rough edges for less common component patterns.
Check @lit-labs/ssr's current documentation for its latest supported feature set before adopting it for a new project.
When SSR Is Worth Adopting
SSR adds real build/deployment complexity, so it's most worth adopting for public, content-heavy, SEO-sensitive pages built with Lit components (marketing sites, documentation, e-commerce product pages) — less so for internal admin dashboards or authenticated application UIs where initial paint speed and SEO matter far less.
Common Mistakes
Accessing browser-only globals inside render() or lifecycle methods without considering that SSR runs in a Node.js environment first.
Assuming @lit-labs/ssr is fully stable and feature-complete, given its experimental/labs status — always verify current support for your specific use case.
Adopting SSR for internal, authenticated application UIs where the added complexity doesn't match the actual benefit.
Forgetting that hydration is a distinct step from initial server rendering — both pieces (server rendering and client hydration) need to be wired up correctly.
Key Takeaways
@lit-labs/ssr renders Lit components to real HTML (including declarative Shadow DOM) in a Node.js environment.
Declarative Shadow DOM (<template shadowrootmode>) lets browsers attach shadow roots during initial HTML parsing, before JavaScript runs.
Hydration reconnects server-rendered markup with client-side Lit reactivity once the component's JavaScript loads.
SSR is most valuable for public, content-heavy, SEO-sensitive pages, and adds complexity worth weighing against the benefit.
Pro Tip
If your project already uses a meta-framework like Astro (which has first-class support for rendering Web Components, including Lit, on the server), prefer that integration over wiring up @lit-labs/ssr manually — it handles most of the hydration wiring for you.
You now understand Lit SSR fundamentals. Next, learn strategies for lazy-loading components to improve load performance.