Skip to content

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.

Call the API
  1. Source codeA string, file or generated content
  2. codeToHtml()Run Ferriki in your build script or server
  3. Highlighted HTMLWrite a static page or send a server response
  4. BrowserDisplay the prepared markup
Prepare examples with Vite
  1. code() or <Code />A literal example in your module
  2. Vite build@ferriki/vite highlights the example
  3. HTML and CSS in the bundlecode(): prepared data · <Code />: shadow code element
  4. BrowserRender without running a highlighter

Requirements

  • Node.js 22.13.0 or newer. Ferriki is ESM-only; use import from a .mjs file.
  • 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