~/blog/digital-garden
Building a Digital Garden with Next.js and Obsidian
How this site turns an Obsidian vault into a blog, a knowledge graph and an AI knowledge base, and a tour of everything a note can contain.

On this page
Welcome to the digital garden. This note doubles as the rendering test page: every kind of content a note can hold is used below, so if something looks wrong here it looks wrong everywhere.
Why a digital garden?
A digital garden is a mix between a personal notebook and a blog. Ideas grow over time and are connected by wikilinks and tags rather than sorted by date. I write in Obsidian on a laptop and a phone, push with Obsidian Git, and Vercel rebuilds the site.

The stack
- Next.js 16 renders the vault at build time.
- Obsidian is the editor; there is no CMS and no admin panel.
- Neon Postgres holds the only mutable data: views, likes, comments, leads.
- Claude answers questions grounded on a knowledge base built from these notes.
| Thing | Lives in | Why |
|---|---|---|
| Posts, case studies, books, papers, photos | CognitiveOS/10_Public/ | plain markdown, portable |
| Images, video, PDFs | 90_System/Attachments/public/ | copied to /content at build |
| Likes, comments, views | Neon Postgres | the only thing that changes without a deploy |
Links are the point
I can use wikilinks between notes, and the site turns them into links, backlinks and graph edges. Linking to a heading works too: the drift workflow. A link to a note that doesn't exist, like a-note-i-have-not-written, renders as muted text instead of a broken link.
Embedding another note gives a card rather than a transclusion:
caseStudy · 2026-02-20 infra-ops: one Terraform + Ansible platform for dev, staging and prod
Media
Video embeds come straight from the vault:
Remote images work with normal markdown syntax, and click to zoom:
Code
export const WIKILINK_RE = /(!?)\[\[([^\]|#\n]+?)(?:#([^\]|\n]+?))?(?:\|([^\]\n]+?))?\]\]/g;
export function* iterateWikilinks(text: string) {
WIKILINK_RE.lastIndex = 0;
let m: RegExpExecArray | null;
while ((m = WIKILINK_RE.exec(text))) yield { embed: m[1] === "!", target: m[2].trim(), heading: m[3], alias: m[4] };
}npm run sync # validates the vault, builds the graph, search index and AI knowledge base
npm run build # prebuild runs sync automaticallyInline code like status: published is the only publishing gate, and highlights survive the trip from Obsidian.
Diagrams
Callouts
Folded by default Click the title to expand. This uses the
[!question]- syntax.
What's next
The system is described end to end in the infra-ops: one Terraform + Ansible platform for dev, staging and prod and lgtm-sidecar: a resource-capped observability stack for small teams case studies; the reading that shaped it is on the bookshelf.
Keep reading
Monthly notes
Get the next one in your inbox.
One email a month on infrastructure, backend design and applied AI. No noise, unsubscribe any time.
Comments (0)
name + comment · no login