Getting started
Bring editor-grade TextMate highlighting to documentation, CMS content, and site builds. Ferriki maintains its own curated grammar catalog and runs it on a native Rust engine: Node.js renders Shiki-shaped HTML, Rust offers a crate API, and Vite 8 macros prepare component examples during the build.
- Source codeA string, file or generated content
- codeToHtml()Run Ferriki in your build script or server
- Highlighted HTMLWrite a static page or send a server response
- BrowserDisplay the prepared markup
- code() or <Code />A literal example in your module
- Vite build@ferriki/vite highlights the example
- HTML and CSS in the bundlecode(): prepared data · <Code />: shadow code element
- BrowserRender without running a highlighter
Requirements
- Node.js 22.13.0 or newer. Ferriki is ESM-only; use
importfrom a.mjsfile. - A supported platform: Linux x64/arm64 (glibc or musl), macOS on Apple Silicon, or Windows x64/arm64. See Compatibility.
Install
npm install @ferriki/core
npm installs the native addon as an optional @ferriki/<platform> dependency.
Keep optional dependencies enabled in your production install.
Language and theme payloads are not bundled. The first time an asynchronous
API loads them, Ferriki downloads release-pinned files from assets.ferriki.dev,
checks their SHA-256 digests, and caches them in
node_modules/.cache/ferriki. For offline builds, prepopulate the cache or set
FERRIKI_ASSETS_BASE_URL to a mirror. Set FERRIKI_ASSETS_REMOTE=0 to use
cached payloads only. See asset loading.
See your first result
Save this complete ESM file as highlight.mjs:
import { writeFile } from "node:fs/promises";
import { codeToHtml } from "@ferriki/core";
const html = await codeToHtml("const answer = 42;", {
lang: "javascript",
theme: "github-dark",
});
await writeFile("highlighted.html", html);
console.log("Saved highlighted.html. Open it in a browser to preview your code.");
Run node highlight.mjs, then open highlighted.html or insert its
<pre> fragment into your page. The first call loads its
language and theme; later one-shot calls reuse the process-local highlighter.
Reuse a highlighter
For a site build or server, create one highlighter with the languages and themes you need. Rendering with loaded languages and themes is synchronous; you can still load more through the asynchronous methods. In a CMS, keep the highlighter for the worker's lifetime rather than recreating it for each code block. The benchmarks measure repeated use.
import { createHighlighter } from "@ferriki/core";
const source = "const answer: number = 42;";
const highlighter = await createHighlighter({
langs: ["typescript", "rust", "css"],
themes: ["github-light", "github-dark"],
});
let html;
try {
html = highlighter.codeToHtml(source, { lang: "typescript", theme: "github-light" });
} finally {
highlighter.dispose();
}
A highlighter belongs to one thread: create one per worker for parallel builds. Dispose it when the build or server no longer needs it.
HTML with CSS
For reusable CSS classes and the matching theme stylesheet, use
codeToHtmlWithCss() or set styleMode: "classes" on codeToHtml(). The
class-based highlighting guide shows complete
HTML and CSS examples, including light and dark theme switching.
The API overview lists every function and option.
Next steps
- Coming from Shiki? Read Migrating from Shiki.
- Code examples in components? Start with Build-time macros.
- Need a language or theme of your own? See Languages and themes.
- Something fails to load? Check Troubleshooting.