From zbeyens. The source code is available on GitHub.

Plate
PlatePliteEditorsTemplates
GitHub16kGitHub
DiscordDiscord
  • Introduction
  • Installation
    • Plate UI
      • Next.js
      • React
    • Manual
    • RSC
    • Node.js
    • Local Docs
    • MCP
  • Releases

RSC

PreviousNext

Install and configure Plate for React Server Components.

Use Plate in React Server Components when you need to render read-only editor content or generate HTML on the server. Interactive editors still belong in client components with platejs/react. This guide shows the server-safe static editor path, HTML serialization, and the boundary with Node-only processing.

RSC Setup

Use static imports

Do not import platejs/react or @platejs/*/react from a Server Component. Use platejs/static, platejs, and base @platejs/* entrypoints.

ManualNode.js

On This Page

RSC SetupInstall the Base KitRender Static ContentSerialize HTMLUse Base Packages Without Plate UIRuntime BoundariesNext Steps
Build your editor
Production-ready AI template and reusable components.
Get all-access

Install the Base Kit

Install the copied base editor kit when you want Plate UI static components and the default serializer plugins.

pnpm dlx shadcn@latest add @plate/editor-plugins-static
pnpm dlx shadcn@latest add @plate/editor-plugins-static

The editor-plugins-static item installs BaseEditorKit, static node components, and the editor-static UI component used by server rendering.

Render Static Content

Create a static editor in the Server Component and render it with <PlateStatic>.

app/documents/page.tsx
import type { Value } from 'platejs';
import { createStaticEditor, PlateStatic } from 'platejs/static';
 
import { BaseEditorKit } from '@/components/editor/plugins-static';
 
const value: Value = [
  {
    children: [{ text: 'Server-rendered document' }],
    type: 'heading', level: 1,
  },
  {
    children: [{ text: 'This content is rendered without editor state.' }],
    type: 'paragraph',
  },
];
 
export default function DocumentsPage() {
  const editor = createStaticEditor({
    plugins: BaseEditorKit,
    initialValue: value,
  });
 
  return <PlateStatic editor={editor} />;
}
app/documents/page.tsx
import type { Value } from 'platejs';
import { createStaticEditor, PlateStatic } from 'platejs/static';
 
import { BaseEditorKit } from '@/components/editor/plugins-static';
 
const value: Value = [
  {
    children: [{ text: 'Server-rendered document' }],
    type: 'heading', level: 1,
  },
  {
    children: [{ text: 'This content is rendered without editor state.' }],
    type: 'paragraph',
  },
];
 
export default function DocumentsPage() {
  const editor = createStaticEditor





Serialize HTML

Use renderStaticHtml when a route needs the server-rendered HTML for a static Plate view instead of a React tree.

app/api/document-html/route.ts
import type { Value } from 'platejs';
import { createStaticEditor, renderStaticHtml } from 'platejs/static';
 
import { BaseEditorKit } from '@/components/editor/plugins-static';
import { EditorStatic } from '@/components/editor/editor-static';
 
const value: Value = [
  {
    children: [{ text: 'Exported document' }],
    type: 'heading', level: 1,
  },
  {
    children: [{ text: 'This HTML is generated on the server.' }],
    type: 'paragraph',
  },
];
 
export async function GET() {
  const editor = createStaticEditor({
    plugins: BaseEditorKit,
    initialValue: value,
  });
 
  const html = await renderStaticHtml(editor, {
    editorComponent: EditorStatic,
  });
 
  return new Response(html, {
    headers: { 'content-type': 'text/html; charset=utf-8' },
  });
}
app/api/document-html/route.ts
import type { Value } from 'platejs';
import { createStaticEditor, renderStaticHtml } from 'platejs/static';
 
import { BaseEditorKit } from '@/components/editor/plugins-static';
import { EditorStatic } from '@/components/editor/editor-static';
 
const value: Value = [
  {
    children: [{ text: 'Exported document' }],
    type: 'heading', level: 1,
  },
  {
    children: [{ text: 'This HTML is generated on the server.' }],
    type: 'paragraph',
  },
];
 
export async function












Use Base Packages Without Plate UI

If you only need data transforms or Markdown IO, use the Node.js path instead of static React rendering.

pnpm add platejs @platejs/basic-nodes @platejs/markdown
pnpm add platejs @platejs/basic-nodes @platejs/markdown

That path uses createBaseEditor from platejs and does not need copied UI components.

Runtime Boundaries

RuntimeImport fromUse for
Server Componentplatejs/staticRead-only React output with <PlateStatic>.
Route handlerplatejs/staticStatic React rendering with renderStaticHtml.
Node scriptplatejs, @platejs/*Validation, migration, Markdown IO.
Client editorplatejs/react, @platejs/*/reactEditable UI, hooks, toolbar interactions.

createStaticEditor includes the static ViewPlugin before your plugins. Use it for rendered output. Use createBaseEditor when the script only reads or transforms a value.

Next Steps

TaskGuide
Learn the static renderer.Static Rendering
Generate HTML.HTML
Read or write Markdown.Markdown
Transform content without React.Node.js

Done. Your Server Component can render Plate content without shipping the interactive editor runtime.

({
plugins: BaseEditorKit,
initialValue: value,
});
return <PlateStatic editor={editor} />;
}
GET
() {
const editor = createStaticEditor({
plugins: BaseEditorKit,
initialValue: value,
});
const html = await renderStaticHtml(editor, {
editorComponent: EditorStatic,
});
return new Response(html, {
headers: { 'content-type': 'text/html; charset=utf-8' },
});
}