This site is where I try things out. When something I build for it turns out useful, I move it into its own package, so the next site gets it with one install instead of a copy-paste.
There are three so far. Two keep their data in Cloudflare D1. The third runs at build time and needs no database. Each one ran on this site first, so if it breaks, my site breaks before yours does.
The packages
Each card links to the GitHub repo. All three install from npm.
Full-text site search. Build-time indexing, an injected search endpoint, and bm25 ranking with a recency boost.
Hearts, unique reads and reader highlights in a pill at the bottom of the page, plus a public stats page.
Drafts, scheduled posts, reading time and git info for content collections. It replaces astro-git-dates.
astro-d1-search
I used to run this site’s search on Algolia. Now it runs on this package, and the search page, the ⌘K spotlight in desktop mode and my Raycast extension all call the same endpoint.
One config object says which content to index and how each source maps to a type and a URL. The integration indexes that content into a D1 full-text table at build time and adds a /api/search route. It also exports a searchIndex function for search pages that render on the server. If the D1 binding is missing from wrangler.toml, it warns at startup and prints the snippet you need.
pnpm add astro-d1-search
There is a docs site (external site). The announcement post covers the setup, and How I replaced Algolia covers how it works.
astro-d1-reactions
This is the pill at the bottom of the page you’re reading. I saw a similar bar on Gabriel Valdivia’s site, loved it, and wanted one on every site I build.
It gives you hearts, a count of unique reads, and reader highlights. Highlights use the CSS Custom Highlight API, so the page’s DOM never changes. There are no cookies and no names. A reader is a random id kept in their browser, so each person counts once per page. The integration adds a POST /api/reactions route and a set of components for a public stats page, like mine.
pnpm add astro-d1-reactions
Both D1 packages need the @astrojs/cloudflare (external site) adapter. The rest of your site can stay static. Only the endpoint and the stats page run on the server. The announcement post has the full setup.
astro-entry-meta
Eleventy and Hugo do a few things for content that Astro doesn’t, and I missed them after I moved this site. This package adds them. You wrap a collection’s loader, and it does three jobs. Each one is opt-in.
- Git dates. Write
date: git Last Modifiedin the frontmatter, and the build swaps in the date of the file’s last commit. - Publishing rules.
draft: true, a futurepublishDateor a pastexpiryDateleaves the entry out of the collection. - Computed fields. Reading time, word count, an excerpt, the last author and an “Edit on GitHub” link, worked out from the entry’s body or its git history.
A content schema can’t see an entry’s body, but a loader can. That’s why these fields live in a loader wrapper. The reading time and edit link on this site’s posts and code notes come from this package. It has no dependencies.
It began as astro-git-dates, which only did the dates. That package (external site) is now retired. The keywords work the same, so moving over is a new import and a new function name.
pnpm add astro-entry-meta
The announcement post shows the setup.
What they share
- Extracted, not invented. I only publish a package after it has worked on this site for a while.
- Small surface. Each one is a single integration or a single loader wrapper, and the setup lives in one place.
- Ready for agents. Each repo has a
SKILL.mdthat teaches a coding agent the setup order, every file to change and the ways it can fail. You can ask your agent to install the package for you. - Static first. The site stays static. Only the pieces that need a server, like search and reactions, run as Cloudflare Workers.
Read more
- Introducing astro-d1-search — search for Astro in one integration
- Introducing astro-d1-reactions — hearts, reads and highlights
- Introducing astro-entry-meta — drafts, reading time and git info
- The Zed Stack — the starters I use to build everything else
- Projects — everything else I’ve made