The blog post about this blog
Try it live (opens in a new tab)
/ 6 min read
Overview
This repo has two jobs. It runs my personal site at lawsonhart.me. It can export a public template without private services, tokens, or hosting assumptions. The repo lives at github.com/lawsonhart/blog-template.
The first version started with Astro and Astro Cactus. That base helped the site ship early. The codebase later grew into custom layouts, components, server routes, search indexing, optional integrations, and daily-use UI work.
That split now shapes the repo. I want one codebase and a clean template. The project works only when both paths stay healthy.
What This Codebase Is Built For
I wanted a site that feels more like a small product than a folder of Markdown files. It needed clean typography, fast search, clear content structure, and room for server routes.
The optional pieces matter most. A template should not ask for my tokens, private endpoints, or hosting setup. The public path stays simple. The site-only path stays isolated.
Template-Safe Features
These parts ship in the exported template and should work for anyone who clones it.
Content Collections For Posts And Notes
Posts and notes use Astro Content Collections. Posts support tags, technologies, cover images, and drafts.
Tags get normalized to lowercase. Duplicate tags are removed. Technologies are deduped in a case-insensitive pass. Draft posts are filtered only in production, so local writing stays flexible.
The technologies field drives the tech icon row on post cards. It gives each post more structure with little authoring cost.
MDX And Markdown Pipeline
I write in Markdown and MDX, and I still want guardrails. The pipeline supports directive admonitions, heading ids with linked headings, safer external links, inline image handling through a public asset prefix, and Astro Expressive Code blocks.
Writing should feel quick. Basic post features should not turn into renderer work.
Search Through Pagefind
Pagefind handles search. The index builds after the site build in scripts/pagefind.mjs.
Search stays off in dev so the local loop stays quick. On the live site, search results match the rest of the UI instead of looking like a pasted-in widget.
This fits a blog template well. Search runs on the client, so there is no search service to run.
Server-Generated OG Images
Posts get OG images from a route that renders them with Satori and Resvg. It sounds small until a shared link shows an empty preview.
After the route exists, every post gets a finished preview image without manual work.
Vercel Deploy And Local Preview
The site builds with output: "server". Production runs on Vercel.
Local preview uses the Node adapter. @astrojs/vercel does not support astro preview in the way this repo needs for a local production check. That is why bun preview swaps adapters, builds, and starts the preview server.
This removes a common point of friction. Template users get a predictable local preview path instead of a production-only check.
What Stays Private
The public template has opinions. Anything tied to my services, private tokens, or narrow site behavior stays out of the snapshot.
That is not about hiding code. It is about shipping defaults that make sense for other people.
Export Flow
template-excludes.txt lists files and paths that should not ship in the public snapshot. scripts/export-template.cjs copies the repo into a fresh folder and filters those paths out.
.env files are excluded as a second safety layer.
The repo has a sandbox flow too. I can test template mode without moving files around by hand. Template-safe code needs regular checks, or the public path drifts.
Site-Only Examples
The exclude list changes as the site changes. The pattern stays the same.
Site-only pieces often include Spotify widgets, GitHub routes and stats, Umami analytics proxy routes, holiday components, comments UI, and posts or project content that do not fit a generic starter.
Those pieces are not magic. They are poor defaults for a public template.
How The Repo Got Here
The commit history follows three clear phases.
Phase One: Product Feel
Early work focused on feel. Search went through several passes until it felt native. Post cards gained reading time and table-of-contents context. The about page changed from a placeholder into a real profile page.
Phase Two: Optional Integrations
The repo gained richer widgets, analytics, GitHub routes, comments experiments, and server-side helpers.
That work exposed the template problem. Every integration helps my site, but each one can make the public repo harder to reuse. A template should not depend on my infrastructure.
The code moved toward soft imports and export filtering. Private features stayed possible without turning the public repo into a setup checklist.
Phase Three: Template Mode As A Requirement
The turning point was tooling. I added a non-destructive sandbox, a real exporter, and build checks for optional files.
After that, the repo stopped being only my personal site. It became a site repo with a template path that has to stand on its own.
Use This As A Template
This is the path I expect most people to take.
Clone And Install
Install Node 20 or newer. Install bun. Run bun install.
The normal local flow uses bun, so install dependencies with bun first.
Update Site Identity
Edit src/site.config.ts. Set the site url, title, author, and description.
Then update navigation links and socials so the header and profile areas match your site.
Add Content
Posts live under src/content/post/**. Notes live under src/content/note/**.
Follow the frontmatter shape in the repo, especially title, description, publishDate, tags, and technologies. Consistent fields keep list pages and cards working without extra tweaks.
Validate The Site
Run bun check for Astro type and content checks. Run bun run build for a production build and Pagefind indexing.
Run bun preview for a local production-style preview.
What The Template Leaves Out
The exported template leaves out comments UI, Spotify widgets, analytics views, and similar site-only pieces by design.
Email me if one of those parts matters for your own site. I can point you to the right slice.
Email: me@lawsonhart.me