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

Node.js

PreviousNext

Install and configure Plate for Node.js conversion and document work.

Use Plate in Node.js to validate, transform, parse, or serialize complete editor documents without mounting React.

Use server-safe imports

Import the editor runtime from platejs, not platejs/react. Markdown uses platejs/markdown. Node HTML parsing uses platejs/html/server.

Install packages

RSCLocal Docs

On This Page

Install packagesCreate a headless editorParse and serialize MarkdownParse HTMLImport DOCXRuntime boundariesRelated docs
Build your editor
Production-ready AI template and reusable components.
Get all-access
pnpm add platejs
pnpm add platejs

Install the optional Markdown peers only when the process converts Markdown:

pnpm add remark-parse remark-stringify unified
pnpm add remark-parse remark-stringify unified

Install the optional HTML server DOM peer only when the process parses HTML:

pnpm add linkedom
pnpm add linkedom

platejs/html/server is ESM. parse5 is a direct Plate dependency; linkedom remains server-only and does not enter browser bundles.

Create a headless editor

scripts/process-content.ts
import { BaseBoldPlugin, BaseHeadingPlugin, createEditor } from 'platejs';
 
const editor = createEditor({
  plugins: [BaseHeadingPlugin, BaseBoldPlugin],
  initialValue: {
    children: [
      { type: 'heading', level: 1, children: [{ text: 'Document title' }] },
      { type: 'paragraph', children: [{ text: 'Body' }] },
    ],
  },
});
 
const document = editor.read.value();
scripts/process-content.ts
import { BaseBoldPlugin, BaseHeadingPlugin, createEditor } from 'platejs';
 
const editor = createEditor({
  plugins: [BaseHeadingPlugin, BaseBoldPlugin],
  initialValue: {
    children: [
      { type: 'heading', level: 1, children: [{ text: 'Document title' }] },
      { type: 'paragraph', children: [{ text: 'Body' }] },
    ],
  },
});
 
const document = editor.read.value();

editor.read.value() returns the complete document, including named roots and persistent metadata. Use editor.update(...) for atomic transformations.

Parse and serialize Markdown

Use direct functions when an editor lifecycle adds no value:

scripts/markdown-io.ts
import { BaseBoldPlugin, BaseHeadingPlugin } from 'platejs';
import { parseMarkdown, serializeMarkdown } from 'platejs/markdown';
 
const plugins = [BaseHeadingPlugin, BaseBoldPlugin] as const;
const parsed = parseMarkdown('# Title\n\n**Body**', { plugins });
 
if (!parsed.ok) throw new Error(parsed.diagnostics[0].message);
 
const output = serializeMarkdown(parsed.document, {
  plugins,
  projection: 'accepted',
});
 
if (output.ok) console.info(output.data);
scripts/markdown-io.ts
import { BaseBoldPlugin, BaseHeadingPlugin } from 'platejs';
import { parseMarkdown, serializeMarkdown } from 'platejs/markdown';
 
const plugins = [BaseHeadingPlugin, BaseBoldPlugin] as const;
const parsed = parseMarkdown('# Title\n\n**Body**', { plugins });
 
if (!parsed.ok) throw new Error(parsed.diagnostics[0].message);
 
const output = serializeMarkdown(parsed.document, {
  plugins,
  projection: 'accepted',
});
 
if (output.ok) console.info(output.data);

Install MarkdownPlugin when several operations should reuse one editor's compiled target:

import { MarkdownPlugin } from 'platejs/markdown';
 
const editor = createEditor({
  plugins: [BaseHeadingPlugin, BaseBoldPlugin, MarkdownPlugin],
});
 
const parsed = editor.api.markdown.parse(source);
const output = editor.api.markdown.serialize({ projection: 'proposed' });
import { MarkdownPlugin } from 'platejs/markdown';
 
const editor = createEditor({
  plugins: [BaseHeadingPlugin, BaseBoldPlugin, MarkdownPlugin],
});
 
const parsed = editor.api.markdown.parse(source);
const output = editor.api.markdown.serialize({ projection: 'proposed' });

Parse HTML

scripts/html-import.ts
import { BaseBoldPlugin, BaseHeadingPlugin } from 'platejs';
import { parseHtml } from 'platejs/html/server';
 
const result = parseHtml(source, {
  plugins: [BaseHeadingPlugin, BaseBoldPlugin],
});
 
if (!result.ok) throw new Error(result.diagnostics[0].message);
scripts/html-import.ts
import { BaseBoldPlugin, BaseHeadingPlugin } from 'platejs';
import { parseHtml } from 'platejs/html/server';
 
const result = parseHtml(source, {
  plugins: [BaseHeadingPlugin, BaseBoldPlugin],
});
 
if (!result.ok) throw new Error(result.diagnostics[0].message);

The server parser and browser parser share one parse5 tree and safety policy. The server adapter does not install ambient DOM globals, execute scripts, or load resources.

Import DOCX

DOCX import is detached and browser/client-only. Supply the complete plugin target in options; do not pass an editor.

import { importDocx } from 'platejs/docx/import';
 
const result = await importDocx(file, {
  plugins: EditorKit,
  signal,
});
import { importDocx } from 'platejs/docx/import';
 
const result = await importDocx(file, {
  plugins: EditorKit,
  signal,
});

Use a browser or client worker for that operation. Server-side DOCX conversion is not implied by the headless editor runtime.

Runtime boundaries

RuntimeImportUse
Node editorplatejsRead, validate, and transform documents.
Node Markdownplatejs/markdownParse and serialize Markdown.
Node HTML parseplatejs/html/serverParse complete HTML documents or slices.
Semantic HTML serializeplatejs/htmlSerialize a detached Plate document.
Static renderingplatejs/staticRender server-safe static components.
React editorplatejs/react, feature /react pathsMounted editing UI and hooks.

Related docs

  • HTML
  • Markdown
  • DOCX
  • Serializing
  • Editor API