Skip to content

Getting Started

Creating a new project

SvelTeX is distributed as a community add-on for the official Svelte CLI (sv). To start from scratch, first scaffold a SvelteKit project:

sh
pnpm dlx sv create
sh
bunx sv create
sh
npx sv create
sh
yarn dlx sv create

...then add SvelTeX to it, as described in the next section.

create-sveltex is deprecated

Earlier versions of SvelTeX shipped a create-sveltex scaffolding package. It has been superseded by the sv add-on below; the create-sveltex binary now only prints a notice pointing here.

Adding to an existing project

Using the sv add-on

The quickest way to add SvelTeX to an existing SvelteKit project is the sv add-on. It installs SvelTeX and the peer dependencies for the backends you pick, creates a sveltex.config.js, and wires the preprocessor into your svelte.config.js:

sh
pnpm dlx sv add @nvl/sv-sveltex
sh
bunx sv add @nvl/sv-sveltex
sh
npx sv add @nvl/sv-sveltex
sh
yarn dlx sv add @nvl/sv-sveltex

...and follow the prompts.

Prefer to set things up by hand? The rest of this page walks through the manual installation and configuration.

Installation

To install SvelTeX, run the following command in your project's root directory (wherever your package.json is located):

sh
pnpm add -D @nvl/sveltex
sh
bun add -D @nvl/sveltex
sh
npm add -D @nvl/sveltex
sh
yarn add -D @nvl/sveltex

SvelTeX doesn't bundle the markdown, code, or math backends — you install the ones you've chosen as peer dependencies. For example, the unified markdown backend needs the unified, remark-parse, remark-rehype, and rehype-stringify packages, the shiki code backend needs shiki, and so on. SvelTeX will tell you exactly which packages are missing the first time you run a build.

MathJax backend

If you pick mathjax as your math backend, you need the @mathjax/src package at version 4 or later:

sh
pnpm add -D @mathjax/src

MathJax v4 ships each math font as a separate npm package, but @mathjax/src already declares @mathjax/mathjax-newcm-font as a dependency — so the default font is pulled in automatically. If you override math.font, also install the matching @mathjax/mathjax-<font>-font package — e.g. for fira:

sh
pnpm add -D @mathjax/mathjax-fira-font

devDependencies is the right scope for both: the CHTML output's font files are served from a CDN at runtime by default (via MathJax's fontURL), and the SVG output bakes glyph paths into the rendered HTML at build time. Either way, the npm packages themselves only need to be present while SvelTeX runs.

See the Math page for details.

Setup

SvelTeX has one main export, sveltex. This is an asynchronous function that takes two arguments:

  1. Backend specification: An object with the following (optional) properties:

    • markdownBackend: The markdown processor to use.
    • codeBackend: The syntax highlighter to use.
    • mathBackend: The math renderer to use. This is different from the full-fledged TeX to SVG pipeline, and intended for simpler math expressions (i.e., expressions that can be rendered with MathJax or KaTeX).
  2. Configuration object: An object with the following (optional) properties:

    • extensions: An array of file extensions to process. Defaults to ['.sveltex'].
    • code: Configuration options for the code backend.
    • markdown: Configuration options for the markdown backend.
    • math: Configuration options for the math backend.
    • tex: Configuration options for the TeX to SVG pipeline.
    • verbatim: Map of verbatim environments to their respective configuration options.
    • frontmatter: Which of SvelTeX's frontmatter-processing steps (head injection, metadata export, import statements) to perform. Pass false to disable frontmatter handling entirely, or an object to toggle individual steps.

In turn, it returns a promise which resolves to a Svelte preprocessor.

Why two arguments?

Splitting the backend choices from the configuration is what makes the config type-aware. The backends you pick in the first argument set the generic types that drive IntelliSense for the second argument, so your editor offers exactly the options each chosen backend supports — and flags the ones it doesn't. Merging everything into one object would throw that inference away.

For example:

js
// sveltex.config.js
import { 
sveltex
} from '@nvl/sveltex';
export default await
sveltex
({
markdownBackend
: 'unified',
codeBackend
: 'shiki',
mathBackend
: 'mathjax'
}, {
code
: {
shiki
: {
theme
: 'github-dark' } },
verbatim
: {
Tex
: {
type
: 'tex',
aliases
: ['TeX'] } }
})

You can then use this export in your svelte.config.js:

js
// svelte.config.js
import { 
vitePreprocess
} from '@sveltejs/vite-plugin-svelte';
import
sveltexPreprocessor
from './sveltex.config.js';
/** @type {import('@sveltejs/kit').Config} */ const
config
= {
// ...
preprocess
: [
vitePreprocess
(), // (optional)
sveltexPreprocessor
,
// ... ],
extensions
: ['.svelte', '.sveltex'],
// ... }; export default
config
;

If you prefer, you can also just use the sveltex function directly in your svelte.config.js. Just remember to await it.

Troubleshooting

A few common first-run snags:

  • The preprocessor seems to do nothing, or Svelte errors that it isn't a valid preprocessor. sveltex(...) is async — it returns a promise that resolves to the preprocessor, not the preprocessor itself. await it (top-level await works in both sveltex.config.js and svelte.config.js):

    js
    export default await sveltex(/* … */); // ✅ awaited
  • Backend options appear to be ignored, or TypeScript complains about the configuration. sveltex takes two arguments — the backend choices first, then the configuration — not a single merged object:

    js
    // ✅ two arguments
    await sveltex(
        { markdownBackend: 'unified', codeBackend: 'shiki' },
        { code: { shiki: { theme: 'github-dark' } } },
    );
    
    // ❌ one object — the backend options silently won't apply
    await sveltex({
        markdownBackend: 'unified',
        code: { shiki: { theme: 'github-dark' } },
    });

    The split is deliberate — it's what makes the configuration fully typed for your chosen backends (see Setup above).

  • A peer dependency is missing. SvelTeX names the exact packages it needs for the backends you picked on the first build — install those and re-run.

  • .sveltex files aren't being processed. Check that extensions in svelte.config.js includes '.sveltex' and that the preprocessor is actually in the preprocess array.