> ## Documentation Index
> Fetch the complete documentation index at: https://docs.webstorio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> The webstorio.config.ts schema — projects, pages, routing, SEO, branding, features, schemas, and dev options.

Every project has a `webstorio.config.ts` at its root. Use the `defineConfig`
helper for full type-checking and autocomplete.

<Note>
  Webstorio pages and components are plain **React** (`.tsx`) — there is no
  bespoke framework to learn. You write standard React and call the global
  [`window.webstorio`](/api-reference/sdk/overview) SDK on the live site; the
  server compiles your code against a pinned set of [supported
  libraries](/api-reference/supported-libraries).
</Note>

```ts webstorio.config.ts theme={"dark"}
import { defineConfig } from "@webstorio/cli/config";

export default defineConfig({
  name: "My Site",
  subdomain: "my-site",
  description: "A short description of your site.",
  components: [
    { file: "components/_header.tsx", slug: "_header", title: "Header" },
    { file: "components/_footer.tsx", slug: "_footer", title: "Footer" },
  ],
  features: {
    header: true,
    footer: true,
    content: true,
    form_and_survey: true,
    online_store: false,
    user_authentication: false,
    app_data: false,
    webstorio_badge: true,
  },
  branding: {
    colors: {
      primary: "#0f766e",
      secondary: "#134e4a",
      background: "#f8fafc",
      text: "#0f172a",
    },
    fonts: { primary: "inter", secondary: "custom:Source Serif 4" },
    brandInfoFile: "brand/brand-info.md",
    designSystemFile: "brand/design-system.md",
    favicon: "favicon.png",
    defaultOgImage: "og-default.png",
  },
  pages: [
    {
      file: "pages/home.tsx",
      slug: "/",
      title: "Home",
      type: "system",
      seo: {
        title: "My Site — Home",
        description: "Welcome to My Site.",
        ogImage: "og-home.png",
      },
    },
    { file: "pages/about.tsx", slug: "about", title: "About" },
    { file: "pages/services.tsx", slug: "services", title: "Services" },
    { file: "pages/contact.tsx", slug: "contact", title: "Contact" },
    {
      file: "pages/blog-detail.tsx",
      slug: "blog/{content_entry_id}",
      title: "Blog post",
    },
  ],
  dev: { dataMode: "dummy" },
});
```

## Fields

<ParamField path="name" type="string" required>
  Human-readable project name. Used as the default SEO title on first create.
</ParamField>

<ParamField path="subdomain" type="string" required>
  Globally-unique subdomain (4–50 chars, lowercase letters/numbers/hyphens).
  This is how `push` finds your project — it's the project's stable identity, so
  one working directory maps to exactly one Webstorio project.
</ParamField>

<ParamField path="description" type="string">
  Optional project description, used as the default SEO description on create.
</ParamField>

<ParamField path="compatibilityDate" type="string">
  A `YYYY-MM-DD` date that pins which [supported
  library](/api-reference/supported-libraries) versions your project targets.
  `webstorio init` writes the current date and `webstorio update` bumps it. The
  server compiles against the version set effective on or before this date, so
  existing projects stay stable as the platform adds newer ones.
</ParamField>

<ParamField path="schemasDir" type="string">
  Optional folder (relative to the config file) of feature schema definitions.
  Expected layout:

  * `content/*.json` — CMS content types (`content`)
  * `forms/*.json` — forms (`form_and_survey`)
  * `data/*.json` — App Data tables (`app_data`)

  When **present**, `webstorio push` upserts schemas by `key`. When **absent**, remote CMS / form / App Data schemas are left
  unchanged.

  Each file is JSON config:

  ```json theme={"dark"}
  {
    "version": 1,
    "kind": "content_type",
    "key": "post",
    "name": "Blog Post",
    "schemaJson": [
      { "key": "title", "type": "text", "label": "Title", "required": true }
    ]
  }
  ```

  Forms may also use the dashboard export shape (`{ version: 1, form: { … } }`).
  `kind` can be omitted when the file lives under the matching folder.
</ParamField>

<ParamField path="components" type="array">
  Shared header/footer component pages. Each entry is
  `{ file, slug, title }` where `slug` is `"_header"` or `"_footer"`. Pushing a
  component automatically enables the matching Webstorio feature so it renders on
  the live site.
</ParamField>

<ParamField path="features" type="object">
  Optional **declarative** map of released [website features](/guides/website-features)
  to enable or disable on push.

  When this field is **present**, it is the desired state for every released
  feature: keys set to `true` are enabled; keys omitted (or set to `false`) are
  disabled. Plan limits still apply (for example, Free cannot turn off the
  Webstorio badge). When the field is **absent**, push leaves remote feature
  flags unchanged.

  Allowed keys: `header`, `footer`, `content`, `form_and_survey`,
  `online_store`, `user_authentication`, `app_data`, `webstorio_badge`.

  If both `components` and `features` are set, `features` is applied after
  component auto-enable and wins (e.g. `features.header: false` disables the
  header even when `_header` is listed under `components`).
</ParamField>

<ParamField path="branding" type="object">
  Optional website branding. When **present**, authored fields are merged into
  the remote website config on push. When **absent**, remote branding is left
  unchanged.

  * `colors` — `{ primary?, secondary?, background?, text? }` as `#RRGGBB` hex.
    Exposed in page code as `bg-brand-primary`, `text-brand-text`, and related
    utilities (live site and `webstorio dev`).
  * `fonts` — `{ primary?, secondary? }` curated keys (`inter`, `open_sans`, …)
    or `custom:Font Family`. Use `font-brand-primary` / `font-brand-secondary`
    in class names.
  * `brandInfo` / `brandInfoFile` — inline markdown or a path relative to the
    config file (use one, not both).
  * `designSystem` / `designSystemFile` — same pattern for the design-system
    markdown.
  * `favicon` / `defaultOgImage` — paths under `assetsDir` (e.g. `"favicon.png"`).
    Use `null` to clear; omit to leave the remote value unchanged.
</ParamField>

<ParamField path="pages" type="array" required>
  Routable pages. Each entry is `{ file, slug, title, type?, seo? }`.

  * `slug` — route path. Use `"/"` for the home page; it is normalized to the
    canonical empty slug on push. Nested routes use `/` between segments (e.g.
    `docs/guide`). Dynamic segments use `{paramName}` (e.g.
    `blog/{content_entry_id}`). See [Routing](#routing) below and the
    [Routing how-to](/developer/routing).
  * `type` — `"static"` (default) or `"system"`. The home page is always
    `"system"`.
  * `seo` — optional `{ title?, description?, keywords?, ogImage? }`. When
    present, push syncs those SEO fields for the page. When absent, remote SEO is
    left alone (new pages still get a seed SEO title from `title`). `ogImage`
    should be a path under `assetsDir`.
</ParamField>

<ParamField path="dev" type="object">
  Local preview options.

  * `dataMode` — `"empty" | "dummy" | "preview"` (default `"dummy"`).
  * `port` — local preview port (default `9678`).
</ParamField>

## Routing

Page URLs come only from `pages[].slug` in this file — not from the filesystem
layout under `pages/`.

| Kind    | Example slug                | Example URL             |
| ------- | --------------------------- | ----------------------- |
| Home    | `"/"`                       | `/`                     |
| Static  | `"about"`                   | `/about`                |
| Nested  | `"docs/getting-started"`    | `/docs/getting-started` |
| Dynamic | `"blog/{content_entry_id}"` | `/blog/abc-123`         |

**Wildcards:** a segment like `{content_entry_id}` or `{product_slug}` matches
any single path segment. Exact static routes take priority over patterns.
`webstorio dev` and the published site use the same matching rules.

Read captured values in page code:

```js theme={"dark"}
const { content_entry_id } = window.webstorio.getPathParams();
```

Feature scaffolds (`webstorio generate` and dashboard create-page) use
conventions such as `content/{key}/{content_entry_id}`,
`store/product/{product_slug}`, and `form/{formKey}`.

Step-by-step guide: [Routing](/developer/routing).

## Shared components

You do **not** list inline shared components (like `Testimonials`) in the
config. Import them from your pages with a relative import and the CLI bundles
them into whichever page uses them:

```tsx pages/about.tsx theme={"dark"}
import Testimonials from "../components/Testimonials";

export default function Page() {
  return (
    <main>
      <Testimonials />
    </main>
  );
}
```

## Supported libraries

Pages and components may only import from Webstorio's allowlist of
[supported libraries](/api-reference/supported-libraries); anything else must be
inlined as a relative import. Run
[`webstorio update`](/cli/commands#webstorio-update) to align your local
`devDependencies` with the exact versions the server compiles against.

<Warning>
  Push fails fast if a page imports a non-allowlisted package or has no default
  export. The server re-validates everything before compiling.
</Warning>
