---
title: "Installation"
description: "Install svedocs in a new project, wire it into an existing SvelteKit app, and keep the framework dependencies current."
---

> Documentation Index
> Fetch the complete documentation index at: https://svedocs.pwp.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Installation

You can generate a new project or add svedocs to an existing SvelteKit app. For a new site, the template is usually faster because it already contains the routes, config, content folders, and server endpoints.

## Requirements

- Node.js 22.17 or newer.
- A SvelteKit project using ESM.
- pnpm, npm, yarn, or bun. The templates default to pnpm because the repository itself uses pnpm.

## Create a new project

```sh
pnpm create svedocs my-docs --template docs
cd my-docs
pnpm install
pnpm dev
```

The `create-svedocs` package forwards the command to `svedocs-cli`. The CLI uses its bundled template, aligns framework and CLI dependency versions, and updates the project name and package manager. Pass `--channel beta` to build from beta packages, or `--channel latest` to prefer latest with automatic beta fallback. Pass `--install` when you also want it to install dependencies.

Every template also includes the current svedocs Agent Skills under `.agents/skills`. Codex discovers them as repository-scoped skills and can use the project-specific setup, configuration, theme, landing, and localization guidance immediately.

Template dependencies are normal registry dependencies:

```json title="package.json"
{
  "dependencies": {
    "svedocs": "latest"
  },
  "devDependencies": {
    "svedocs-cli": "latest"
  }
}
```

With `--install`, your chosen package manager installs these packages from its configured registry. No framework source is copied into the project.

All three templates pin Wrangler to the repository-validated version so the Cloudflare adapter peer dependency does not select an incompatible runtime. When upgrading Wrangler, verify Miniflare/workerd, edge builds and prerendering together.

## Choose a template

```sh
pnpm create svedocs my-docs --template minimal
pnpm create svedocs my-docs --template docs
pnpm create svedocs my-docs --template cloudflare
```

| Template | Included routes | Best for |
| --- | --- | --- |
| `minimal` | Docs shell, sitemap, robots, and optional RSS routes. | Learning the basics or embedding docs into an existing app. |
| `docs` | Search, Ask AI fallback, sitemap, robots, optional RSS, and OG routes. | Most product documentation sites. |
| `cloudflare` | Everything in `docs`, plus Wrangler config and Cloudflare binding examples. | Cloudflare Pages and edge-first projects. |

Remote template behavior can be controlled with environment variables:

| Variable | Purpose |
| --- | --- |
| `SVEDOCS_TEMPLATE_SOURCE=bundled` | Force the CLI-bundled template copy. |
| `SVEDOCS_TEMPLATE_SOURCE=github` | Require GitHub and fail instead of falling back. |
| `SVEDOCS_TEMPLATE_REF=<branch|tag|sha>` | Pin a remote template version. |
| `SVEDOCS_TEMPLATE_REPOSITORY=<owner/repo>` | Fetch templates from a different repository. |

## Add svedocs to an existing app

Install the framework and CLI:

```sh
pnpm add svedocs
pnpm add -D svedocs-cli @tailwindcss/vite tailwindcss
```

Create `svedocs.config.ts`:

```ts title="svedocs.config.ts"
import { defineConfig } from 'svedocs/config';

export default defineConfig({
  site: {
    name: 'My docs',
    title: 'My docs',
    description: 'Documentation for my product',
    url: 'https://example.com'
  },
  content: {
    root: 'content',
    docs: 'content/docs',
    pages: 'content/pages'
  },
  ai: false
});
```

Register the Vite plugin:

```ts title="vite.config.ts"
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import tailwindcss from '@tailwindcss/vite';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { svedocs } from 'svedocs/vite';
import { svedocsPreprocess, svedocsSvelteExtensions } from 'svedocs/svelte';
import svedocsConfig from './svedocs.config.ts';

export default defineConfig({
  plugins: [
    svedocs({ config: svedocsConfig }),
    tailwindcss(),
    sveltekit({
      adapter: adapter(),
      extensions: svedocsSvelteExtensions,
      preprocess: [vitePreprocess(), svedocsPreprocess()]
    })
  ]
});
```

Import the default theme CSS once in the root layout:

```svelte title="src/routes/+layout.svelte"
<script lang="ts">
  import 'svedocs/theme/styles.css';
  import type { Snippet } from 'svelte';
  let { children }: { children: Snippet } = $props();
</script>

{@render children()}
```

Keep your existing SvelteKit plugins and layout content when merging these changes. This minimal setup enables local search and disables Ask AI until you add its runtime route.

SvelteKit 3 keeps adapter, extension and preprocessor settings in `sveltekit({ ... })` inside `vite.config.ts`. Keep your existing adapter when merging this example, or install `@sveltejs/adapter-auto` as a dev dependency. It requires Node.js 22.17+, Svelte 5.57+, Vite 8 and TypeScript 6.x. Remove the old application `svelte.config.js`, change `$lib` imports to `#lib`, use `$app/env` and `$app/state`, and extend `$app/tsconfig` in `tsconfig.json`.

Add native subpath imports to `package.json`; TypeScript/JavaScript imports need a file extension (for example `#lib/server/env.js`). Set `"extends": "$app/tsconfig"` and `"include": ["src/**/*.ts", "src/**/*.svelte", ".svelte-kit/**/*.d.ts"]` in `tsconfig.json`.

```json title="package.json"
{
  "imports": {
    "#lib": "./src/lib/index.js",
    "#lib/*": "./src/lib/*"
  }
}
```

### Server document attributes and route options

Set document language and direction on the server so prerendered HTML and JavaScript-disabled requests have the same semantics. Compose existing server hooks with `sequence`; preserve authentication, agent negotiation and cache behavior.

```ts title="src/hooks.server.ts"
import { createSvedocsHtmlHandle } from 'svedocs/routes';
import config from 'virtual:svedocs/config';
import pages from 'virtual:svedocs/page-index';

export const handle = createSvedocsHtmlHandle({ config, pages });
```

```ts title="src/routes/+layout.ts"
import { svedocsSsr, svedocsTrailingSlash } from 'svedocs/cloudflare';

export const ssr = svedocsSsr();
export const trailingSlash = svedocsTrailingSlash();
```

Generated templates include this wiring. Edge page URLs omit the trailing slash; static and SPA page URLs include it, with `/` unchanged. Known pages retain SSR/prerendered content for readers and crawlers without JavaScript.

### Load the current document

Create the catch-all route below. It resolves localized URLs, returns a real 404 for unknown documents, and loads only the current page and its content component. Existing SvelteKit routes take precedence over the catch-all.

```ts title="src/routes/[...path]/+page.ts"
import componentLoaders from 'virtual:svedocs/component-loaders';
import layoutLoaders from 'virtual:svedocs/layout-loaders';
import { loadSvedocsPage } from 'svedocs/routes';
import { error, redirect } from '@sveltejs/kit';
import config from 'virtual:svedocs/config';
import pageLoaders from 'virtual:svedocs/page-loaders';
import pages from 'virtual:svedocs/page-index';
import tree from 'virtual:svedocs/tree';
import { svedocsPagePrerender } from 'svedocs/cloudflare';
import type { SvedocsPage } from 'svedocs/core';
import { createSvedocsRouteEntries, resolveSvedocsPageRoute } from 'svedocs/routes';
import type { PageLoad } from './$types';

export const prerender = svedocsPagePrerender(undefined, config);

export function entries() {
  return createSvedocsRouteEntries(pages, config)
    .map((path) => ({ path: path.replace(/^\//, '') }));
}

export const load: PageLoad = async ({ params }) => {
  const routePath = `/${params.path ?? ''}`.replace(/\/$/, '') || '/';
  const resolution = resolveSvedocsPageRoute(routePath, pages, config);
  if (resolution.status === 'redirect') redirect(307, resolution.location);
  if (resolution.status === 'missing') error(404, `No page found for ${routePath}`);
  const pageIndex = resolution.page;
  const loaded = await loadSvedocsPage(pageIndex, { pages: pageLoaders, components: componentLoaders, layouts: layoutLoaders });
  const { page } = loaded;
  return { ...loaded, pages: mergeCurrentPage(pages, page), search: [], tree, config };
};

function mergeCurrentPage(pages: SvedocsPage[], current: SvedocsPage): SvedocsPage[] {
  return pages.map((page) => page.id === current.id ? current : page);
}
```

### Render the document

Pass the loaded page and theme components to `DocsApp`. The search index loads when needed.

```svelte title="src/routes/[...path]/+page.svelte"
<script lang="ts">
  import { DocsApp } from 'svedocs/theme';
  import themeComponents from 'virtual:svedocs/theme-components';
  import loadSearch from 'virtual:svedocs/search-loader';
  export let data;
</script>

<DocsApp page={data.page} pages={data.pages} tree={data.tree} search={data.search} config={data.config} content={data.content} layout={data.layout} {themeComponents} {loadSearch} />
```

Add `src/app.d.ts` if the project does not already reference the virtual module types:

```ts title="src/app.d.ts"
/// <reference types="svedocs/virtual" />
```

The route now serves content under `/docs` and standalone content pages that do not overlap existing routes. The app can retain its current home page. Add [search and Ask AI endpoints](/docs/integrations/search-ai), [SEO routes](/docs/integrations/seo-og), and [agent routes](/docs/integrations/agent-interface) when needed; generated templates include this wiring.

## Add content

Create the content roots and a first docs page:

```sh
mkdir -p content/docs content/pages
```

```md title="content/docs/index.md"
---
title: Introduction
description: Start here to understand the product.
order: 1
---

# Introduction

Welcome to the docs.
```

## Verify the installation

Run these commands before adding hosted integrations:

```sh
pnpm check
pnpm build
```

`pnpm check` runs the application’s Svelte and TypeScript checks. Run `pnpm exec svedocs check --strict` separately for broken content links, missing descriptions, and translation gaps. Open `/docs` with `pnpm dev`, then run `pnpm build` to verify the integration with the existing adapter.

## Upgrade svedocs

Generated projects include both `svedocs` and `svedocs-cli`. Upgrade them together:

```sh
svedocs upgrade
svedocs upgrade 0.2.0
svedocs upgrade 0.2.0 --no-install
svedocs upgrade --check-only
```

Before changing dependencies, the upgrade command checks whether the requested version crosses a known breaking release. There are no special migration rules yet; future releases can add them when needed.

## Troubleshooting

| Symptom | Check |
| --- | --- |
| The docs page renders without styles. | Confirm `svedocs/theme/styles.css` is imported from the root layout. |
| Routes do not update while editing content. | Confirm `svedocs({ config })` is registered in `vite.config.ts`. |
| Search route works locally but not in production. | Confirm provider credentials or Cloudflare bindings exist in the runtime environment. |
| Build fails in `spa` mode. | Prefer `edge` or `static`; use `spa` only for constrained hosts that need a fallback. |


## Upgrading from 0.2

Version 0.3 requires SvelteKit 3 and Node.js 22.17+. Follow the [SvelteKit 3 migration guide](https://svelte.dev/docs/kit/migrating-to-sveltekit-3), then merge the configuration and route patterns shown above. For Cloudflare, also migrate runtime bindings to `cloudflare:workers` and preserve the static/SPA fallback alias from the generated template.

`svedocs upgrade` updates the framework and CLI packages together; it does not rewrite SvelteKit configuration or upgrade the rest of your dependencies. Keep TypeScript on 6.x, update the SvelteKit adapters, and run type checks, a production build, and browser navigation checks before deploying.

Source: https://svedocs.pwp.sh/docs/installation
