Project structure

A new site has only a few of these; add the others when you need them.

PathWhat it holds
kilim.config.tsTitle, url, theme, plugins and changes to the theme's collections.
content/Markdown files, one page each; posts in content/posts/.
settings/Theme settings, one file per theme, e.g. default.yaml.
public/Files copied to the site as they are: images, fonts, downloads.
redirects.txtRedirects from old URLs, one from to pair per line.
styles/critical.css (inlined) and main.css added after the theme's CSS.
layouts/Extra layouts in TSX, next to the theme's.
overrides/Replacements for the theme's layouts, partials, components and blocks.
components/Markdown components, used as :::name in content.
blocks/Page sections for frontmatter blocks.
themes/Local themes, used with theme: "<folder>" in the config.

Kilim writes two folders you should not commit:

  • dist/: the built site, ready to upload.
  • .kilim/: caches (images, fonts, compiled layouts), the build manifest kilim check reads, the admin's trash and the generated types.

The config

kilim.config.ts exports the config through defineConfig, which gives type completion for every option and the rules of your plugins. A new blog's config is the site's own details and the theme:

import { defineConfig } from "@kilim-dev/core";

export default defineConfig({
  title: "My Blog",
  url: "https://example.com",
  description: "A fast, static blog built with Kilim.",
  theme: "default",
});

The theme brings the collections: pages (every page in content/) and posts (content/posts/), and any of its own. The config only lists what it changes; see Using a theme.

The config is checked when it loads, and an error names the option, e.g. kilim.config.ts: "trailingSlash" must be a boolean. Config options lists every option.

url is the address the site is published at: canonical links, the sitemap, feeds and Open Graph tags use it. Leave out the path; the build warns when it is missing.