September 2025 to April 2026 Recap - Forms, elm2nix, and more
Hey folks,
I hope my newsletters aren't too frequent, :D, but I had a few new things I wanted to share.
When I completed the Frontend Mentor's Contact form challenge I switched gears and focused my efforts on trying to improve the user experience between Elm and Nix. During that time I learned a lot about Elm, Nix, and even Haskell as I attempted to rebuild cachix/elm2nix from the ground up.
After announcing dwayne/elm2nix I worked on incorporating it into several of my projects and tried to help other developers in the Elm community adopt it in their projects. There's a lot more work to do but the feedback has been great so far.
There were a few other projects I worked on and blog posts that I wrote but I'd tell you more about them in the sections below. So, let's get into it.
Frontend Mentor's Contact form challenge
When I last shared my update in the August 2025 Recap I was building Frontend Mentor's Contact form challenge as a practical example of how to use my field and form libraries. I'm now happy to report that I've completed the application and it's hosted at Elm Frontend Mentor Contact Form.
The implementation showcases how to create custom fields like Data.Contact.Email, Data.Contact.QueryType, and Data.Contact.Text. How to handle custom error messages like Data.Contact.Error. And, how to put it all together in a form like Data.Contact.Form.
The most interesting thing about the implementation, at least for me, is that the business logic of the form is independent of the way the form is to be rendered. The form is rendered in View.Form and you can see how the fields are just data structures that are queried to construct the UI.
As a consequence of the separation of concerns, you can write unit tests to check that the form satisfies its business requirements. I've illustrated that in Test.Data.Contact.Form.
Some benefits of this approach include:
- You can write libraries of custom fields to reuse across your applications. Think custom email, URL, phone number and address fields as examples.
- You can write libraries of custom forms to reuse across your applications. For example, a login form. You write and test the business logic once.
- Error messages can be written in multiple languages at the time of use and don't have to be decided upon during implementation.
elm2nix
dwayne/elm2nix is a complete rewrite of cachix/elm2nix. It follows standard Nix patterns for writing builders and makes it easy to build and package your application as a Nix derivation.
These are some of the notable differences:
- You can input one or more
elm.jsonfiles to create the lock file. - It uses a JSON formatted lock file that has support for multiple versions of the same package.
- You don't have to manually generate a
registry.datfile since it's automatically handled for you. - You can display any
registry.datfile as JSON usingelm2nix registry view. - There is a
buildElmApplicationbuild helper that allows you to build an Elm application in a variety of ways by setting options. For e.g. - Turn on the time-travelling debugger - Fail the build if your Elm source code is improperly formatted - Fail the build if your Elm tests fail - Fail the build ifelm-reviewfails - Turn on optimizations - Useelm-optimize-level-2instead ofelm make --optimize- Enable minification with UglifyJS or Terser - Enable compression with gzip and brotli - Show a report about the changes in your file size due to minification and compression - Enable content hashing for cache busting purposes - Or completely customize portions of the build to your liking if you know howstdenv.mkDerivationworks - You can easily use
lydell/elm-safe-virtual-domin your projects. More generally you can patch any published Elm package and make use of them in your projects.
@turbo_mack had this to say about the project on the Elm Slack:
I finally found some time to test
https://elmlang.slack.com/archives/C0K384K4Y/p1775745746409309@dwayne’s version of elm2nix and it's a big improvement. I managed to build our production app with it. It uses webpack with a ton of stuff and all sorts of crazy things like complicatedsource-directoriesattribute in elm.json. It took very little to make an integratednpmandelmbased build to work. I'm impressed.
I also spent time adding dwayne/elm2nix to my projects and other people's projects. In particular, I rewrote "The Classics" and I figured out a seemless way to use Simon Lydell's elm-safe-virtual-dom when I helped Flavio Corpa adopt dwayne/elm2nix in his elm-countries-quiz project.
What does dwayne/elm2nix enable for your Elm web applications?
- You can now run your Elm web application from any machine with Nix installed. For e.g. try
nix run github:dwayne/elm-todos. - CI becomes more reliable. In Towards more reliable CI, Evan shares straightforward approaches for making CI much more reliable. With
dwayne/elm2nixyou're effectively doing the same thing because you're given a way to reproducibly cache the packages your application depends upon. - You can more easily work with patched Elm packages. For e.g.
lydell/elm-safe-virtual-dom. - You can vendor Elm packages.
- You can work with private packages.
- You can create Nix flake templates of your best practices.
Deploy static websites
I got tired of copy-pasting my deployment Bash script so I packaged it with Nix. I primarily use it for deploying my Elm web applications under GitHub Pages and Netlify but it can be used for deploying any static website under Render, Cloudflare, and others as well. You can check it out at dwayne/deploy.
What's nice about this is that I'm effectively using Nix to package and distribute my Bash script in a reproducible and reliable way. Here's how I use it:
- In a project, I add it as a flake input.
- I use
writeShellScriptto create a derivation that uses my Bash script. - I output the derivation as an app that I can run using
nix run .#deploy.
Elm Queues
I've needed queues several times in the past so I decided to extract a small library, dwayne/elm-queue, with an API fit for my needs. It ended up inspiring Martin Janiczek to test and benchmark all the queue packages and he wrote a blog post, Elm Queues Shootout!, about it.
Mine passed all the tests and did well performance wise but it ultimately wasn't recommended because it didn't have a rich enough API. So now I'm going to add N more helper functions. I'd be picking N so that with N-1 helper functions Martin still doesn't pick my package but with N he picks my library to be his favourite :D.
Web Awesome
I explored Web Awesome usage with Elm. According to Web Awesome, Web Awesome is the biggest open source library of meticulously designed, highly customizable, and framework agnostic UI components. The naming is apt, because that's really awesome for the web. It's also awesome for Elm because the lack of UI frameworks for Elm has been a real hinderance in the past.
The conclusion I came to was that I feel comfortable recommending Web Awesome usage with Elm. And, in general, I feel comfortable recommending web component usage with Elm.
- Slots worked
- Attributes and properties worked
- Method calling worked via both port and synchronous method calling
- Custom events worked
- CSS custom properties worked
- CSS parts worked
- The components I used worked:
wa-button,wa-color-picker,wa-icon,wa-tab-group,wa-popup, andwa-popover - Switching the icon set to Lucide worked
You can see for yourself in my Elm and Web Awesome Playground.
Brainfuck
I implemented a Brainfuck interpreter. It showcases Elm's data modeling capabilities, uses an unbounded memory model, provides an example of using elm/parser, includes an extensive test suite and is built with Parcel and Nix.
From the blog
As you might expect, I blogged mainly about dwayne/elm2nix during this time.
- Frontend Mentor's Contact form challenge built with Elm - I share how I used my field and form Elm packages to complete Frontend Mentor's Contact form challenge.
- Announcing
dwayne/elm2nix- An announcement about my rewrite ofcachix/elm2nixwith a few changes and improvements. - Making TodoMVC work with
dwayne/elm2nix- I describe the work that was done to usedwayne/elm2nixin my TodoMVC Elm web application and the improvements that resulted from the change. - Nix + pnpm + Parcel +
lydell/elm-safe-virtual-dom- I describe the improvements I made tokvothe/elm-countries-quizto integrate it with Nix + pnpm + Parcel +lydell/elm-safe-virtual-dom. - Elm + Nix: A reproducible RealWorld clone - I share how I refactored my RealWorld clone to use Nix.
- Writing more readable parsers in Haskell using keep and skip from
elm/parser- It shows how thinking in terms of keep and skip can make your Haskell parsers easier to read and write.
Built with Elm
On Built with Elm, 4 new projects have been added.
- Seat Savvy - A classroom seating chart tool.
- LunarTasks - A task management system for recurring, non-urgent tasks (that eventually become urgent).
- RepoDash - Monitor commits across several GitHub repositories.
- Kana Party - A "Match 3" game for learning Japanese.
Thanks again to everyone who shared their projects.
Picks
Calling WebAssembly functions from Nix
Determinate Nix added builtins.wasm. Nix is Turing complete but it was never intended as a general-purpose language. For complex programming tasks, it lacks the conveniences of modern languages like Rust. builtins.wasm provides a better way to extend the Nix language through the power of WebAssembly. This allows you to extend Nix with any language that compiles to WebAssembly, for e.g. Rust, C++, and Zig. Or Grain.
Grain
Grain is a strongly-typed functional programming language that compiles directly to WebAssembly.
That's it for today. I wish you all the best this month and remember, make haste slowly.