Developer's Reference
For: Developers who configure or extend Kukui (config, build, generators, theme).
In this guide you'll: See Kukui's markdown capabilities in action, understand the three-file config model, the build pipeline, generators, and CLI — and where to extend (MDX components, Tailwind, theme).
Markdown capabilities showcase
Kukui supports rich content via custom directives and MDX. This page is built from the same markdown — each block below is a live example you can copy into your own notes.
YouTube directive
Embed a responsive YouTube player. Syntax: <Youtube id="VIDEO_ID" title="Title" />.
Foster City, California
Mermaid diagram
Flowcharts, sequence diagrams, and more. Shown here: a small flowchart via the directive.
Build flow
You can also use a fenced code block:
Drop cap
Style the first letter of a paragraph. Default: ::dropcap. Inverted: ::dropcap[inverted].
Kukui turns your Obsidian folder and assets into a static site. Write in Markdown, use wikilinks and directives, then build and deploy to S3, CloudFront, or any static host. The developer reference documents the config model, build phases, and CLI so you can extend or troubleshoot the pipeline.
SVG directive
Embed an SVG from your assets. Example: the Kukui logo from the skeleton.
Syntax-highlighted code
Fenced code blocks get syntax highlighting (e.g. IBM Plex Mono, Monokai-style). Use them for commands and config.
yarn dev
yarn generate:nav
yarn build{
"siteRoot": "./sites",
"defaultSiteId": "example.com"
}Showcase directive (carousel)
Embed a carousel from a JSON data file. The skeleton provides showcase-home.json; this is the showcase directive with that data.
Loading showcase...
Configuration model
Kukui uses three config sources. There are no legacy fallbacks (e.g. no obsidian-site-config.json, no deploy config in .env for S3).
| File | Location | Purpose |
|---|---|---|
| system-config.json | Project root | siteRoot — path to the directory that contains sites.json and all site folders |
| sites.json | Under site root | defaultSiteId; sites map: per-site hostname, basePath, s3 (bucket, region), cloudfront (distributionId), optional dynamodb, outDir, rsync (host) |
| content.json | Per site: <siteRoot>/<siteId>/content.json | Theme, cdn (hostname, basePath), siteURL, ogImage, footer, masonry/carousel defaults, etc. |
Precedence: System → sites → content. S3 bucket and CloudFront ID come only from sites.json for the active site (no .env overrides). Set SITE_ID or DEPLOY_SITE when you have multiple sites.
Minimal system-config.json:
{
"siteRoot": "./sites"
}Minimal site entry in sites.json:
{
"defaultSiteId": "example.com",
"sites": {
"example.com": {
"hostname": "example.com",
"basePath": "",
"s3": { "bucket": "example.com", "region": "us-east-1" },
"cloudfront": { "distributionId": "E1XXX" }
}
}
}Optional: tailwind.config.json (or .js) per site under <siteRoot>/<siteId>/ to override Tailwind (merged with base config).
Project and site structure
- Monorepo:
packages/site(Next.js app),packages/build-tools(generators, watch, sync),packages/deploy-tool(S3/CloudFront deploy),packages/core(shared config/types). - Site root = path from
system-config.json→siteRoot. Each site ID is a subdirectory:<siteRoot>/<siteId>/. - Per-site directory:
obsidian/(content),assets/(images, audio, data, svg),content.json, optionaltailwind.config.json, and after build an out directory (or path fromsites.jsonoutDir).
Build phases
- prebuild (before Next.js): Build core packages; sync site data from site root; copy assets to
public/; generate theme CSS; generate album index, audio index, navigation data. - build: Next.js static export — reads from
public/and generated data, writes to the site-specific output directory (e.g..next/<siteId>/then migrated if needed). - postbuild: Migrate Next.js output to final out path if needed; generate build-info; run route verification (optional fail if critical routes missing).
Next.js with output: 'export' copies public/ into the export; assets don’t need a separate postbuild copy step.
Generators
| Generator | Command | Triggered by (examples) |
|---|---|---|
| Navigation data | yarn generate:nav | Markdown changes (watch) |
| Image renditions | yarn generate:renditions | Image add/change |
| Album index | yarn generate:albums | Album folder / album.json / images |
| Audio index | yarn generate:audio | Audio folder / playlist.json |
| Build info | yarn generate:build-info | Build / postbuild |
Run all: yarn generate. Inspect what runs for a file: yarn query-deps <file-path>; yarn query-deps --graph or --list for the full dependency graph.
CLI reference
| Command | Description |
|---|---|
yarn dev | Start dev server (site selector or --site <id>) |
yarn watch | File watcher; auto-runs generators, invalidates Next cache |
yarn query-deps <path> | Show which generators run for a file; --graph / --list for graph |
yarn generate | Run all generators |
yarn generate:albums | Album index only (and :audio, :nav, :renditions, :build-info) |
yarn build | Full build (prebuild + Next.js + postbuild) |
yarn preview | Serve the built site locally |
yarn wizard | Interactive menu (first run can provision a site from skeleton) |
yarn deploy | Build and deploy to S3 + CloudFront (uses sites.json) |
yarn deploy-rsync | Deploy via rsync (uses sites.json rsync.host or DEPLOY_HOST) |
Common flags: --site <siteId>, --sites-root <path>, --force (for generators).
Route verification
After the build, verify-routes can run (postbuild): it checks that expected routes (from navigation data) have corresponding HTML in the out directory. You can enable fail on missing and define critical routes in sites.json under a verification object. Use yarn workspace @obsidian-site/build-tools verify-routes for manual checks (e.g. --verbose, --fail-on-missing).
Environment variables
| Variable | Purpose |
|---|---|
| SITE_ID / DEPLOY_SITE | Active site when multiple sites exist |
| SITES_ROOT | Override site root path (otherwise from system-config) |
| DISABLE_SYMLINK | Set to avoid symlinks in dev (e.g. permission issues) |
| VERIFY_ROUTES | Enable route verification (default on) |
| FAIL_ON_MISSING_ROUTES | Fail build/deploy if critical routes missing |
| VERBOSE_BUILD | More verbose build output |
S3 bucket, region, and CloudFront distribution ID are not set via env — they come from sites.json for the selected site. For rsync only, DEPLOY_HOST can override rsync.host.
Extending
- Content and nav: Content lives in the obsidian folder and assets; navigation is generated from folder structure and frontmatter.
- Theme: Site-level content.json (theme name or inline theme); optional tailwind.config.json per site.
- MDX components: Add components (e.g. in
packages/site/components/mdx/) and register them so they’re available in markdown; the live examples in this doc use the same directive pipeline. - New directives: Implemented in the site package (directive parsing and React components); see existing directives (youtube, mermaid, svg, showcase, etc.) as reference.
See also
- Quick-Start-Guide — Get running
- Authors-Guide — Content and directives from an author’s perspective
- Deployment-Guide — Deploy commands and CI/CD
- Troubleshooting — Config, build, and deploy problems