Weeknotes: Webbplats update (part 2)
Jun 30, 2026
I wrote a few weeks ago about wanting to move the OCaml based software I wrote to host this and my other websites, called Webbplats, over to OCaml's new Effect based I/O system (EIO). My motivation for doing so was simply that EIO is built by a bunch of my colleagues and so I wanted to learn what they'd been up do. The main promise of EIO as a user is that it handles blocking I/O without littering your code with promises or async/await annotations, rather your code that uses it just reads like a regular blocking I/O implementation, but under the hood EIO is juggling things to make it all work nicely. Obviously if you don't tell it to do something else whilst waiting then it will just be like a blocking implementation, but if you're using an EIO library, like say a web server library that is EIO aware as I'm about to, then that library can do the scheduling bits and your request handling code can remain quite linear.
The challenge, as I documented before, was that I was previously using Dream, an OCaml web framework that handled both the HTML rendering from templates and the plumbing of requests to page responses. In that previous post I went over how I swapped out the HTML rendering part to use Htmlit, and so what remained was to change the backend over from Dream to Cohttp with its EIO backend.
The change from Dream to Cohttp was more than just changing the HTTP request handling functions, as I needed to switch all my IO operations to being EIO based rather than using either traditional blocking I/O requests using OCaml's standard library, or using the promise based LWT library upon which Dream is based. This is where some of the given and take of EIO starts to become evident: whilst your code flow does get simpler, EIO requires you work with a set of contexts (a file system context, a process manager context, etc.) that you get passed in from your main entry point, and you have to propagate those throughout your code. Now, you can argue that if you're doing functional programming or unit testing properly then you shouldn't really have side-effects littered through your code, and so using these passed around contexts for I/O makes sense (and it does), but it does make the code slightly messier than it might otherwise be. And there's some nice security niceties here: the file system context EIO provides can have its scope constrained so your code can only access a subset of the file system, so overall I approve, but it was interesting to see how I traded one set of code clutter for another - though for me it's definitely a better kind of clutter.
The process did remind me that I've not really gotten OCaml properly into my head. Whilst I enjoy using OCaml as a language, there's a lot of power in the type system that I've not really interacted with and internalised, meaning I'm probably making poor use of the language overall. In using EIO I hit upon some bits about polymorphic types and constraints upon them I'd not seen before which I had to work through to understand (and this is ignoring the fact I still haven't tried to use GADTs yet). This is somewhat the curse of being a generalist: I have to spend my time hoping between languages and I kinda miss the time I worked for five years writing fairly low level Objective-C code and knew the language and frameworks inside out. But that's not really what's needed of me in my current role, and I enjoy learning about climate science enough that I'll accept the trade off.
Anyway, moving all of Webbplats to EIO was a slow task because of all this: not only do I change where the I/O happens, I also have to trace it through the system, and whilst type inference helps, I had to update all my internal types too (because I took a slightly silly route of letting all my types be polymorphic rather than just going for concrete EIO types).
But it all works now, at least if you can read this then it is working :)
There's more I should do, as the code is basically a naive replacement of one thing with another, and only in a few places did I make EIO specific optimisations - I hope I can do more of that in the future. The one thing that did bite me was Camlimages has a conflicting dependancy with EIO, and so I had to finally remove that from my code, but I'd already done that once when I was on a Raspberry Pi and Camlimages was too slow, and so I just reverted to the previous stop gap of calling external tools for image processing.
Tags: weeknotes, self hosting, webbplats, dream, eio