# Enable CMS
Adds an inline-editing CMS with an admin bar, served from the app's own backend or a hosted one.
Tags: sveltekit, cms, content, inline-editing, sqlite, velastack

$ vela enable cms

## Tutorials

- [How to let clients edit a SvelteKit site themselves](https://velastack.dev/tutorials/sveltekit-let-clients-edit-content)

## src/lib/cms.ts

```ts
import { apiAdapter, createCms } from "@velastack/cms/server";

/**
 * The CMS read path, called from the root `+layout.server.ts`.
 *
 * `/api/cms` is where `src/routes/api/cms/[...path]/+server.ts` mounts the
 * backend. It is also the admin bar's default, so the endpoint is named here
 * and nowhere else.
 *
 * `locales` lists every locale the site supports; the first is the default
 * that a missing translation falls back to.
 */
export const { load: loadCms, generateEntries } = createCms({
  adapter: apiAdapter({ endpoint: "/api/cms" }),
  locales: ["en"],
});
```

## src/lib/server/cms.ts

```ts
import { dataPath } from "@velastack/kit/server";
import { createCmsBackend } from "@velastack/cms/backend";

/**
 * The CMS HTTP backend, mounted single-tenant at `/api/cms` by
 * `src/routes/api/cms/[...path]/+server.ts`.
 *
 * Same origin as the site, so there is no CORS to configure and the session
 * cookie is first-party. Editors sign in against the backend's own
 * `cms_editors` table — add one with `vela cms editor add <email>`.
 *
 * `dataPath` reads `VELA_DATA_DIR`, which `vela` sets wherever it runs the
 * app, so the database and uploads live in the data directory that outlives
 * a release rather than inside the build.
 */
export const cms = createCmsBackend({
  dbPath: dataPath("cms.sqlite"),
  uploadDir: dataPath("uploads"),
});
```

## src/routes/api/cms/[...path]/+server.ts

```ts
import { cms } from "$lib/server/cms";

// `fallback` catches every method, including OPTIONS. The backend does its own
// sub-routing off `params.path`, so a new endpoint never touches this file.
export const prerender = false;
export const fallback = cms.handler;
```

## src/routes/uploads/[filename]/+server.ts

```ts
import { cms } from "$lib/server/cms";

// Uploads land in the data directory after the build, so no static handler
// would find them. Media URLs written into content are root-relative
// `/uploads/<file>`, which is what this route serves.
export const prerender = false;
export const GET = cms.serveUpload;
```
