Home Writing

til / rewrite using the BETH stack

About a year and a half ago, I rewrote this site using Remix and I was happy with the code. But, recently, I’ve been intrigued by htmx and wanted a project to test it on. A couple of weeks ago a video popped up in my recommendations on YouTube, The BETH Stack by Ethan Niser, which piqued my interest and I started doing some rewrite tests during my vacation.

The stack is very much on the bleeding edge:

But, I haven’t had any big issues, even if they are bleeding edge. The main issues have been with Elysia and the lack of documentation, but functionality wise it’s been great once I understood how to use it.

I had zero issues with Bun and they will release it’s 1.0 on September 7, so I’ll consider it stable enough for use.

htmx #

That part that I was most excited to try was htmx and I haven’t been disappointed. I can’t tell how it will work for a larger scale app (but others have used it with good results), but for the scale of a simple blog it’s a great match.

I’m not shipping any JavaScript to the client (other than htmx of course) and I still get the same experience as the Remix version. I would argue that the code is simpler and it’s easy to handle custom events like:

Debounce #

This is a code example from my admin interface where I can write blog posts and get a rendered preview while writing.

  • hx-get defines a GET to /admin/preview which returns rendered Markdown
  • hx-target tells htmx which element, using a CSS selector, to update with the response
  • hx-trigger says that the GET should be triggered on keyup, if the value has changed, and after a 500ms delay.
<textarea
  hx-get="/admin/preview"
  hx-target="#preview"
  hx-trigger="keyup changed delay:500ms"
>
  Text here
</textarea>
<div id="preview"></div>

Keyboard shortcuts #

Keyboard shortcuts are simple to add (hint: use ctrl + n / ctrl + p to navigate between blog posts, or test cmd + k to open a simple command menu).

  • href – A regular link, but I’m boosting which makes all anchors and forms perform AJAX requests instead. This makes the site faster, since it doesn’t have to process scripts or styles on navigation and instead only replaces the content of body with the response.
  • hx-trigger – Trigger on clicks and (comma-separated events) on keyup when the control key and the n-key are pressed. from:body takes advantage of event bubbling and captures the event on body. Without it, ctrl + n would only work on the anchor itself.
<a
  href="/posts/:next-slug"
  hx-trigger="click, keyup[ctrlKey && key == 'n'] from:body"
>
  Next title
</a>

Tip #

I can recommend Hypermedia Systems if you want to learn how to use htmx and the history and thinking behind creating hypermedia driven applications. It can be read for free online.

Database and ORM update #

I was using PostgreSQL as my database, but Turso uses a fork of SQLite instead. The migration was simple and I mainly needed to adjust my date and boolean fields. 1

Prisma has been my go-to ORM the last couple of years. The BETH Stack used Drizzle and I decided that I wanted to test that as well, since I was also going to migrate to Turso. I have to say that I’m very very happy with the change. It feels more like writing raw SQL and a big positive is that it supports real joins (which Prisma doesn’t). Drizzle will likely be my ORM of choice in the future.


  1. Edit: I did switch to Turso. It worked perfectly and was fast, but their pricing is based on row reads/writes and some of my queries incur a lot of reads, especially the ones on the stats page. Loading the stats page meant over 200 000 row reads. This could just be me writing inefficient queries and/or lacking good indexes, but it prompted me to switch back to my Postgres DB which I still had for other projects. The free tier has a generous 1 billion row reads / month, but it can add up quickly if your queries affect lots of rows. ↩︎


  • Loading next post...
  • Loading previous post...