The Perfect Stack

Dear Dave,

I will preface this by saying this is unequivocally the perfect stack for every project in every situation. No nuance or qualifications. It can’t be perfect if you have to think about it.

Without further ado, here’s the perfect stack:

  • Bun
  • Hono
  • HTMX


The perfect stack obviously needs to use the perfect language, JavaScript. We want to use the same language on the client and server because having to know more than one language is not ideal. TypeScript takes a perfect language and makes it even more perfect by adding an inscrutable type system. Now, you could use a tried-and-true runtime like Node to actually execute this prefect, beautiful language, but it’s more perfect to use a runtime that has just only recently reached 1.0—Bun.

Bun has everything you could want. It has a package manager. It has a test runner. It has support for TypeScript. It has a built in SQLite driver. It has a bundler that doesn’t support CSS. But most importantly, it’s written in Zig, a language so fast you’ve never heard of it. It’s got it all.


While you can easily write a server with Bun, Hono is the perfect framework. What’s cool about it? It’s got a simple and familiar API, but also JSX support for server-side rendering. Now, I’ve been touting the benefits of SSR for weeks now, and React devs have been spreading the good news of JSX for decades. Finally, for the first time ever, they come together. You can use JSX to generate HTML on the server. With TSX, you can get your beautiful TypeScript types as you write your templates.

app.get("/", (c) => {
    return c.html(
            <Search />

It’s really quite simple. No awkward templating languages” that don’t give you any help at all. Just beautiful JSX.

But, can we make it more perfect? Yes. Add Drizzle ORM and Zod. The perfect stack doesn’t make you think, and that includes having to think about SQL. Drizzle does so much for you, including generating migrations and TypeScript types from table schemas. It can even generate Zod schemas which can be used in Hono endpoints to safely parse request data.

export const favoriteMovies = sqliteTable("favorite_movies", {
    id: integer("id").notNull().unique(),
    title: text("title").notNull(),
    release_date: text("release_date").notNull(),
    poster_path: text("poster_path").notNull(),
export type Movie = InferSelectModel<typeof favoriteMovies>;
export const insertMovieSchema = createInsertSchema(favoriteMovies, {
    id: z.coerce.number(),
});"/favorite", zValidator("form", insertMovieSchema), async (c) => {
    const movie = c.req.valid("form");

    await db.insert(favoriteMovies).values(movie);
    return c.html(<MovieItem movie={movie} favorited={true} remove={false} />);

Using zValidator , it will automatically parse the form data and return an error if it’s wrong. You can validator other parts of the request too—queries, params, json body, headers, etc.

If that’s too perfect, you can write a custom validator function to have more control:

const searchSchema = z.object({
    search: z.string(),
    validator("form", (value, c) => {
        const parsed = searchSchema.safeParse(value);
        if (!parsed.success) {
            return c.text("Invalid!", 401);
    async (c) => {
        const { search } = c.req.valid("form");
        const results = await searchForMovie(search);
        const favorites = (await =>;
        return c.html(<Search results={results} favorites={favorites} />);


If you’re not using HTMX, what are you even doing with your life? Instead of a server sending JSON to your JS framework and making it figure out how to render the new data, send HTML. Lots of HTML or little bits of HTML, it’s all good! Browsers are good at HTML. HTMX makes HTML more powerful. It reduces the amount of JS you need on the client by a lot. We want lots of JS on the server, not the client, the way Al Gore intended. Perfect.

Just like this, you can make a DELETE request and remove the DOM element if successful.

        hx-target="closest li"

Don’t shoot the messenger, but sometimes JS on the client makes things better. We don’t want too much though. That’s why the perfect stack uses AlpineJS when necessary. Making your HTML harder to read is a great deterrent to adding more JS. Little sprinkles is all you need. That is chef’s kiss perfection right there.

What about styles? Add PicoCSS and never look back. Never think about CSS again. What’s that? You do want to think about CSS? Then use Open Props so you don’t have to think too much.

The Perfect Stack

So there we have it—the perfect stack. Never thought I’d live to see the day, but sure am glad I did before the AIs took over. I’ve been using it for well over 2 days now and have had zero problems, because it’s perfect.

To summarize:

  • Bun
    • SQLite
  • Hono
    • JSX
    • Drizzle ORM
    • Zod
  • HTMX
  • Alpine.js
  • PicoCSS

If you want to see more or give it a try, check out the repo.

If this doesn’t sound perfect to you, you’re wrong, but just use Astro. Less perfect, but probably good enough for what you’re doing.

P.S. Why is GitHub’s default tab spacing eight spaces!? Screenshot of GitHub appearance preferences showing default tab width of 8 spaces

Web Development

What I Use to Blog in 2024

I have 2 blogs/sites. runs on and runs on Ghost.

The thing that attracted me to Blot was that it unifies the writing, editing, and publishing experience. Mine is setup to watch a Dropbox folder. So whenever a file in that changes, the site updates. I use iA Writer for writing, so I just add and edit markdown files in that Dropbox folder and they automatically publish. Really simple.

Automatic publishing is also the downside. Unless I put an underscore in the filename or in a special drafts folder, it will get published—including images. I don’t love managing and adding images, so that has a bit more friction. I have to be careful how they get named. Since it’s all flat markdown files, you have to manage the frontmatter and metadata yourself. I have a couple scripts to scaffold out new markdown files they way I like and where I want them, but still, more friction.

Theming is also quite difficult and not well documented. I’ve tried multiple times and never been able to get a local instance of Blot running to make theme development easier. There might be a better way, but basically, I make changes, wait for the site to rebuild, and see if they are the changes I want. Not ideal.

But, one of the fastest ways to go from idea to published post.


I started thinking I’d go with Astro and Pages CMS. After dealing with markdown files for years, Pages CMS looks like a great way to hide that ugliness. But I really didn’t like the idea of bringing every piece and configuring and all that—making sure I have all the right SEO tags, the RSS feed generating correctly, etc. I wanted something a little more battle tested and stable. So thought I’d try Ghost. I got it running yesterday, so not a ton of experience, but that certainly doesn’t disqualify me from talking like I know things right?

Setup was quite simple (once DNS is fully propagated.) They have a one-click droplet on Digital Ocean that made it simple, plus the Ghost CLI manages updates too. Seems to be one of the easier blogs to self-host. Their host is like $300/yr for a plan that includes custom themes, so not an option IMO. I had one small hiccup with images not uploading. Turns out I needed to manually install the sharp package with npm for some reason.

Seems to have room to grow—membership and newsletter support.

I created a custom theme mostly from scratch without too much trouble. They have a lot of helpers that manages a lot of the head content for SEO which is great.

It still seems easy to post, but a little more friction IMO. You need to go through their editor to publish, but iA Writer is able to upload drafts. So I can write in iA Writer, upload, then go to the site to clean up and publish. But that complicates my workflow a bit. Now iA Writer is full of draft” files that don’t match what is published since it doesn’t sync—just one-way. Not sure how to deal with that yet.

But Ghost is definitely robust and full-featured, and pretty simple.

iA Writer

I use iA Writer and like it quite a bit. But it’s not perfect. I wish it could sync with Ghost instead of just publishing drafts. I have no clue how to manage my files after I publish them. Do I delete them since they are no longer the source of truth? IDK, something I need to work through. I sometimes get lost in the file browser. But actually writing in it is fantastic. I love their Quattro font. I currently have no plans to switch to anything else.

So there you have it. My blogging infrastructure in 2024. Thanks for stopping by.


State Of the Blogs 2024

It’s been 215 days since my last post on here. I had been posting pretty regularly for nearly a year up until the end of August 2023. Mostly was writing dev logs for my app ScreenCred. But other stuff too. And then, I think I just broke?

Towards the end of August, I started thinking about becoming more serious” about blogging. I thought I wanted part of my identity to be that I was a blogger. I was going to start a new series called Low Power Mode. The idea was to write about getting things done will minimal energy. I have a folder full of notes and ideas. I drafted 5 or 6 posts. I made updates to my site to be able to highlight this new series. I was ready to go.

Then I wasn’t.

Honestly, still not totally sure what happened—maybe I should figure that out? But I think the gist is that once again, I just burned out and shut down. It sounded like too much work. It felt restrictive. It felt permanent for some reason. I could see the signs that this was going to be no fun at all.

I kinda stopped everything I was doing. Stopped working on ScreenCred. Stopped working on my Obsidian plugin. Stopped bookbinding. Stopped blogging.

Ron Swanson saying “I hate everything”The internet let me down and couldn’t find a gif of Ron Swanson saying 'This will be no fun at all.'

I filled that time with reading. I read like 25 books. Just needed to reset.

Ron Swanson throwing a computer into the dumpsterNot quite this bad. But not not this bad.

Like I’ve written about before, my blogging desires come and go. And seriously seem to coincide with the seasons. It’s spring now, so I guess I feel like blogging again. In fact, I started a new blog.

Lemon Point Bricks

2024 is is the year of LEGO for me. And I decided that involves blogging about LEGO. So spun up Lemon Point Bricks.

I tried Instagram, but I just don’t get it anymore. I want a blog to be my primary outlet. Ownership and open web and all that good stuff. Will still occasionally post on Instagram. Check it out and let me know what you think…if I can figure out a way for you to send me feedback.

Since I’m not doing much programming in my free time anymore, I need to de-emphasize dev logs on here. I’ve now got my LEGO blog and so this will be my whatever else blog. Stuff that is uninteresting to anyone but me. Going to try and take things chill.

Ron Swanson saying “I’ve said too much” and walking awayI guess I relate to Ron Swanson

Well. TMI. So, see ya later. But probably soon.


Devlog: September 10, 2023

A friend of mine likes to say every app either starts or ends as a spreadsheet.”

My wife and I have a spreadsheet we use to track our savings and what we are savings towards. The best feature of this spreadsheet is that it projects when we will meet our goals. I didn’t set things up perfectly, so it’s gotten out of sync and the projections are wrong right now. I thought this might be a nice thing to convert to an app of some sort.

I recently read Hypermedia Systems1. It got me hyped to try out Htmx. I got a Go server running with Fiber, added Htmx, Alpine.js, and Picocss. I was ready to go.

I started thinking things through in my thinking chair. A line from Hypermedia Systems came to mind. Under the section When Shouldn’t You Use Hypermedia?” The authors write, One example that springs immediately to mind is an online spreadsheet application.”


It still could be done, but probably not the best idea to start with.

What did I end up doing? During a work meeting that I didn’t really need to pay attention to, I took 10 mins and fixed the logic in my spreadsheet. It now appears to calculate things correctly. This was the right solution.

Now I need to find a new project to try Htmx on. I’m sure I could still make this project work with Htmx, but I want to try it on something it is especially well-suited for.

  1. If you can get over the overuse of emphasis in the book, I think this is a worthwhile read and I quite enjoyed it. Not only did the ideas and philosophies speak to me, I thought they did a good job of answering every question I had about Htmx going into it.↩︎


Devlog: August 30, 2023

I worked on my blog layout today. As much as I love Blot, developing a custom theme is not very simple. I’ve never been able to get the local Blot environment running, so my dev process is make a change, wait for it to update on my live site, then check to see how it is 😬.

I wanted to update my homepage so that I could have sections for different tags. Right now I’m envisioning one section for devlogs, one for some up coming stuff, and then everything else. The Blot templating uses Mustache—which I don’t really understand—and also doesn’t provide me a lot of control. So for only showing the first 3 devlogs, I have to actually put all of them in the DOM, then use CSS to hide all but the first 3.

    <div class="recent-post">
        <a href="{{{url}}}">{{title}}</a>
.recent-post:nth-child(n+4) {
    display: none;

Not the most elegant, but works.

I would like to redesign my whole blog, but without a solid local dev experience, it really sounds like a chore. I’ve looked around for other CMS options, but publishing with Blot is so gosh darn easy, everything else looks archaic in comparison. So may need to spend more time working on getting Blot running locally.


Review of Amazon Basics 3 Hole Punch, Semi-Adjustable, 30 Sheet Capacity, Black

For reasons I don’t want to get into now, I need a 3 hole punch for A5 sized paper. The Amazon Basics 3 Hole Punch, Semi-Adjustable, 30 Sheet Capacity, Black seemed to fit the requirements. With the appealing advertised capacity and the amount of adjustment available for the holes and alignment guide, I thought this would be just right. But, I was wrong. It’s being returned.

Amazon Basics 3 Hole Punch, Semi-Adjustable, 30 Sheet Capacity, BlackNot too bad looking

My first impressions after getting it out of the box were positive. It has some weight to it and feels solid.

However, the first hole punch was disappointing.

Dirty residue around the hole punchWhat even is that?

It left some dark residue. One white paper, it’s really noticeable. Maybe this will clear up after more use, but not a great first experience.

The next thing I noticed was the alignment guide.

Sliding alignment guide with markings for common paper sizesAlignment guides

You can’t tell from the picture, but the alignment guide has notches, so it kinda locks into place when you get to one of the presets. It has notches for if your paper is 8 inches, 8 ½ inches, or 220mm, and so on. The problem? A5 paper is 210mm. Which is right in the middle of the 8 inch and 8 ½ inch notches. It’s a bit difficult to keep at 210mm. It can easily be knocked into another notch and you alignment is now off.

Not the end of the world. I could live if the holes weren’t perfectly centered and aligned. I could make the 8 ½ inch notch work if I had to.

Then I noticed that the holes are inset quite a bit more than my other hole punch. It’s about ⅛” difference. That’s quite a bit when you’re dealing with a small A5 sized sheet. This was the biggest down side for me.

Two pieces of paper with holes punched in them, stacked to show the one eighth inch difference in how far the holes are inset from the edge of the pageThe holes are just inset too far

So all these things combined, this hole punch is going back in the box and being returned. The search continues.


Picture of Sam Warnick

As my daughter says, I'm just a tired dad, with a tired name, Sam Warnick. I'm a software developer in Beaufort, SC.

Some things I do