In case you’ve seen my two previous posts where I attempted learning in public of RedwoodJS, you probably realized just as I did that the span of 1-2 hours was simply too small to really explore something - especially as I was making the notes as I was doing the exploration, which (while helping me clarify my thoughts and immediate next steps) was further slowing me down. Also, it was too arbitrary - I didn’t really have a real goal (the app I was thinking of building was a fun one, but one that I had zero actual need for).

Before last Christmas, I suddenly wished I could learn React. The frontend was not completely new to me - several years ago I built a small app with Angular, before I wrote some interactive frontends in jQuery and then vanilla JS. And as the aspect of courses goes, I had a pretty great experience with pricey-but-top-notch Total Typescript from Matt Pocock, which to date had been the best course I’ve done and which taught me to actually think in declarative types as opposed to my previous, strictly nominal experience. I therefore bought Epic React from Kent C. Dodds, and it was even better, worth every penny. (Maybe I one day will try to summarize what made these two courses stand out so much, and why the React one was even better than the TS one). But anyway, I decided to really dedicate my full focus to it, and booked a full consecutive five days for Learning&Development which Lokalise offers. (Previously, I had only ever taken one at a time.) The learning was very intense and super fun. After the five days, I had a solid foundation and as the Christmas holiday began, I thought that I’d like to practice.

In 2018 (or maybe even earlier), my dad was looking for a web designer for his philosophy blog project, existence-transcendence.cz. Back then, I created it with what I knew, which was server-ful PHP on the backend, Latte templating language compiled to HTML and vanilla / jQuery JS on the frontend. (The graphics was done by a friend of mine.)

During the course, Kent C. Dodds mentioned Remix a few times, so I was very intrigued. I decided to rewrite the blog into Remix. It turned out to be crucial that this was a real project, because I had to spend quite a lot of time on the rewrite (dozens of hours) and the motivation was much bigger than be it something for the sake of learning only. Also, it was pretty great that I was just rewriting an existing project, not creating a completely new one, because learning several completely new technologies (as I’ll explain later) and at the same time coming up with architecture and business logic of a new project would simply be too much challenge for me (there’s this nice saying that too small a challenge is boring, too big a challenge is frustrating, so big-but-not-too-big a challenge leads to most growth while it feels very rewarding and engaging).

As I’ll unpack over the course of several upcoming blogposts (I realized there was no way to fit all the information in a single one), it was not only Remix which I had to learn. My journey began by searching for Remix hosting, as I had no clue how this would be done - previously, I have only ever worked on server-ful apps, even our Node.js app in Lokalise is server-ful. Moreover, dad’s current hosting was about 35 EUR a year for both DB and PHP server, so I wanted to match or undercut that price. But what I found was very often just a JS hosting, not offering a DB, plus usually quite pricey (~30 EUR a month for a Node.js server = 12x more). I had basically no mental model for what to search for, how to think about connecting the DB to it and whether looking into serverless even was an option, but as I kept reading, it made more and more sense, as the blog definitely didn’t need a server running 24/7 (it’s a very niche one, with only several visits per day).

At one point I ran into Render.com, which seemed to have a free tier (which after a trial period turned out to be rather unusable) and offered a DB. Yay! But I wasn’t really sure what “stack” of Remix to use - at one point, I found that there are several stacks, with my use case probably being best served by the “indie stack”. And yay, there was a Github template of it - and double yay, Render had its own fork of it! So that’s where I started from. The template contained Prisma or Drizzle, I’m not 100% sure. But - the template was built on Remix 2, while I was hoping to find Remix 3 (or React Router 7 - to this day, this evolution and merging of the two projects remains a bit confusing to me). While researching on how to upgrade, or what the relationship of Remix and React Router even is, I came across another hosting provider, Netlify. It looked very nice, with a free tier and had a React Router 7 template! But - no DB.

At this point, things were already starting to click together one by one in my mind. (I love this phase of learning - after a longish period of vagueness, the pieces intuitively start to form a mental model of the problem.) Maybe I can just use a completely separate DB hosting! But what DB to use? One template, I don’t remember which it was, had Drizzle instead of Prisma. I’m familiar with Prisma, not with Drizzle. So I thought, why not, let’s learn this new thing as well. The setup wasn’t flawless however, and as I kept looking around the Drizzle homepage, I noticed that they integrate with (and probably are sponsored by) Gel. I clicked to learn more about it (why not after all, that’s how deliberate learning works after all) and wow, did it look interesting! It felt like all other databases are from the 20th century while Gel was finally a 21st century citizen. I’ll share more about what I liked about it, but very soon I also realized that Drizzle will have to use it very generically, as it needs to conform to the other adapters’ interfaces. So I decided to ditch an ORM and jump head-first into using Gel specifically. (Vendor lock-in, I know… especially with all the super unusual features offered by Gel. But I couldn’t resist, looked too interesting.)

Finally, I decided I won’t use any of the “Remix stack” templates, and that it’s fine to just hook everything together myself. I’m still not used to this after all the years in PHP world: in the frameworks I worked with, everything had its place and best practice, in JS not so much. I used Netlify’s React Router 7 template and added the DB integration on my own - after all, this goes in line with the premise of Remix/RR7 that it takes care of your view and controller layers of your MVC, not about the model layer. (Maybe that’s also part of why RedwoodJS appealed to me - it felt similar to how Symfony dictates just about everything and it’s therefore very standardized and simple to use).

At some point, I decided it should be fine to use serverless. I didn’t have a real mental model about it, and the one I’ve built since might just as well have gaps, but it didn’t feel so confusing to me anymore - basically, there will be just some point of time where some JS runtime is invoked and processes the request using Remix’s backend. That is powered by Vite (I’m still not sure what role does Vite actually fulfill there). The thing that confuses me is probably that there’s a build which is deployed to the hosting, while when executed, it creates some HTML to send to the client, which also contains some <script> tags which the browser follows and downloads to the client - the distinction of what is and is not being sent to the browser and in what form (resulting HTML / JSON vs .js build artifacts) feels still somewhat hazy to me. But that wasn’t blocking me anymore - I thought I’ll just try it (I’m not sure if Netlify even offers server-ful deployment) and see.

And boy oh boy, does the end result feel awesome. This blogpost is doomed to fail to convey the sheer joy I felt when programming in Remix, but to at least try, I need to mention that I had already forgotten just how much excitement there can be in programming - and this, after probably many years, brought me this excitement back.

I was thinking on how to describe what I like so much about Remix, and I’d probably say “the perfect amount of magic”. Years ago - possibly as far back as 2014 - I was writing one of my first paid projects, and as I freshly heard that loading a XMLHttpRequest was faster than a full page load, I manually wired my app in a way that worked that way. It was very unnatural in the PHP framework I was using, I’m sure there were many flaws (navigating back in browser history comes to mind) and there had to be plenty of fragile, custom JS to make this work. I haven’t done that since - until now, where I found that this is exactly how Remix works. Except for Remix, this way of working is how it’s built - no fiddling around with custom boilerplate code, it just works. But there is not too much magic, in the sense of not knowing why something is happening - everything is very transparent and built on the foundations of how HTTP itself works. (This is something that’s extremely appealing to me, Remix’s principle “Use the platform”, where they mention you’ll be spending more time in MDN docs than in Remix’s own. A perfect example I’ll return to in one of the upcoming posts is the session).

And (this is probably not all thanks to Remix, a lot is definitely because of server-side-rendered React) the way that the framework decides what can be rendered on the backend side already and how it’s then brought to life after it’s hydrated on the frontend seamlessly is just jaw-dropping for me. Previously in the PHP world, I had to be very intentional about what happens on the server side (of course, the distinction was easy - what was written in PHP was happening on the server side) and what and how is sent in a HTML to the browser and how it’s brought to life by the javascript I had to write separately. In Remix / SSR React? Not at all! I just write what I want the code to do (that’s part of React’s declarative nature, I suppose) and it happens. Incredible. I don’t really have to think of it, I just focus on the end experience. (I’m sure a real Remix professional is aware of this on some level and is able to utilize that knowledge to optimize the resulting experience even more - but for now, I’m not at that stage.)

Alright, this is it for today. I hope I piqued your interest, more posts will follow!


Note: Gel database was originally named EdgeDB and rebranded in February 2025. I updated this post with the new name on March 1st.