Skip to content

Developer's Reference

Config, build pipeline, CLI, and live showcase of Kukui markdown capabilities

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.

Kukui logo

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"
}

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).

FileLocationPurpose
system-config.jsonProject rootsiteRoot — path to the directory that contains sites.json and all site folders
sites.jsonUnder site rootdefaultSiteId; sites map: per-site hostname, basePath, s3 (bucket, region), cloudfront (distributionId), optional dynamodb, outDir, rsync (host)
content.jsonPer site: <siteRoot>/<siteId>/content.jsonTheme, 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.jsonsiteRoot. Each site ID is a subdirectory: <siteRoot>/<siteId>/.
  • Per-site directory: obsidian/ (content), assets/ (images, audio, data, svg), content.json, optional tailwind.config.json, and after build an out directory (or path from sites.json outDir).

Build phases

  1. 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.
  2. 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).
  3. 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

GeneratorCommandTriggered by (examples)
Navigation datayarn generate:navMarkdown changes (watch)
Image renditionsyarn generate:renditionsImage add/change
Album indexyarn generate:albumsAlbum folder / album.json / images
Audio indexyarn generate:audioAudio folder / playlist.json
Build infoyarn generate:build-infoBuild / 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

CommandDescription
yarn devStart dev server (site selector or --site <id>)
yarn watchFile watcher; auto-runs generators, invalidates Next cache
yarn query-deps <path>Show which generators run for a file; --graph / --list for graph
yarn generateRun all generators
yarn generate:albumsAlbum index only (and :audio, :nav, :renditions, :build-info)
yarn buildFull build (prebuild + Next.js + postbuild)
yarn previewServe the built site locally
yarn wizardInteractive menu (first run can provision a site from skeleton)
yarn deployBuild and deploy to S3 + CloudFront (uses sites.json)
yarn deploy-rsyncDeploy 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

VariablePurpose
SITE_ID / DEPLOY_SITEActive site when multiple sites exist
SITES_ROOTOverride site root path (otherwise from system-config)
DISABLE_SYMLINKSet to avoid symlinks in dev (e.g. permission issues)
VERIFY_ROUTESEnable route verification (default on)
FAIL_ON_MISSING_ROUTESFail build/deploy if critical routes missing
VERBOSE_BUILDMore 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