How my personal website is architected and built.

thumbnail for

Site Architecture

My site is built with NextJS (with strict TypeScript enabled). It's deployed and served with Vercel.


I use a variety of JavaScript libraries and frameworks:


  • Default (sans): Poppins
  • Mono: Jet Brains Mono
  • Serif: Gelica


All of the content files are written in Obsidian flavored Markdown. They're copied from the Obsidian vault directory on my local machine into my content directory with a custom script. The script can run ad hoc but it's also run as a git pre-commit hook using Husky (JavaScript).

The content is stored in version control simply to reduce storing and fetching it from somewhere else.

  • All notes except posts are copied into content/notes/<DIRECTORY PATH>/<FILENAME> and served as /notes/<SLUGIFIED FILENAME>/
  • All posts are copied into content/posts/<FILENAME> and served as /posts/<SLUGIFIED FILENAME>/

When the site builds, the paths are flattened out.

As an example, the file for the content you're currently reading lives in the vault path 40 - Projects/ When the content is served, it will be served at notes/

Serving content at the notes root makes the URL path durable. I can move it into a different directory and the URL path will persist at the same location it did before.


I use a few scripts to stitch everything together:

  • A script to copy my Obsidian files with status: published into my git repo's content directory
  • A script to generate my RSS feed from the files in my content directory
  • A script to fetch content from Dropbox ([DEPRECATED in preference of the script above])

I was originally using Obsidian Publish and serving the site Using and NGINX for Proxying Obsidian Publish but found the solution wasn't meeting my needs.

For durability purposes, I created a Netlify site that uses _redirects to redirect my paths from to


This is an Obsidian Dataview section that allows me to keep tabs on what's published and if it's missing metadata.

dv.table(["Note", "Description"], dv.pages().filter((p) => p.status === "published").map(p => [, p.description]))
dv.list(dv.pages().filter((p) => p.status === "published" && !p.description).map(p =>


  • 2022-10-05 - added "notes" to the homepage

Was this page helpful?

Subscribe to my Newsletter

Every other week I publish the Curiously Crafted newsletter.

In it, I explore the intersection of curiosity and craft: the people who make stuff, what they make and the way they pursue the craft of making.

The curious logo of Chase Adams: glasses and a bow tie.stay curious.