
Saas cookbook
I enjoy doing open-source side projects, and over time I've ended up reaching for more or less the same stack every time. This is an attempt to write it down — partly so I stop making the same decisions from scratch, partly because the individual bits are interesting on their own and I'd like to dig into each one in a later post.
The goal is to keep the project either self-hostable or runnable as a hosted service, without paying for anything until there's a reason to.
The pieces I end up needing every time:
- A website with docs.
- Somewhere to run the API and the database.
- An admin dashboard for managing the service.
- An npm package for consumers to install.
- A starter template so spinning up a new project is one command.
The website
The website is almost always mostly static, so any of the usual static site generators work — Docusaurus, VitePress, Nextra. They're all fine. The friction for me is always editing: committing markdown files by hand never quite feels like writing.
My current pick is Outstatic, which feels like a classic CMS on top of a static site — a web UI that pushes markdown commits to GitHub. It's newer and lacks some features the others bundle (search, for one), but those aren't too hard to add. I wrote about wiring up FlexSearch against it.
Hosting: Vercel's free tier is fantastic right up until it isn't — the big gotcha is that it won't let you deploy from a GitHub organisation on the free plan, which surprised me. I've been meaning to try Cloudflare Pages as an alternative, which should be similarly easy and meaningfully cheaper once you start paying.
The API and the database
This one's the most opinionated slot, and it's entirely down to what you're used to. My current JavaScript/TypeScript stack:
- Hono with @hono/zod-openapi. Hono leans on web standards wherever it can, which means the same app runs on Cloudflare Workers, AWS Lambda, Bun, Node, or Docker without much ceremony. The zod/openapi plugin gives you request validation, TypeScript types and an OpenAPI spec from a single schema. That feels like a cheat code.
- SQLite via Drizzle for storage. SQLite is plenty for the workloads I'm actually running, Drizzle generates real SQL migrations you can read, and on Cloudflare it maps straight onto D1. I wrote up the migrations setup separately.
The admin dashboard
Nothing surprising here — a small React app talking to the API. The thing I want to get right is generating the forms and tables from the OpenAPI spec rather than hand-coding every screen. With zod schemas already describing every request, most of the dashboard can be generated. That's a post for another day.
The npm library
For anything that's meant to be consumed by other projects, the library boils down to two things: a typed client for the API (again, generated from the OpenAPI spec), and a small amount of glue for auth and errors. I use changesets in a pnpm monorepo to version and publish it.
The starter template
Last piece: a create-<thing> command that scaffolds a new project with the library already wired up. npm create conventions make this cheap — it's just a package that copies a template directory.
That's the whole stack, at a high level. Each of these deserves its own post, and I'll link them back here as I write them.