todomvc-nix: One-Stop Solution for Developing Projects Using Nix
Andika Demas Riyandi
TL;DR; I refreshed the
todomvc-nixproject, add full-stack Rust, and Haskell frontend. TodoMVC is a project that includes implementations of a simple TODO application, in various languages. The
todomvc-nixproject takes these examples and shows how to build them using Nix. Both as a developer environment, and build-system. This should give a good starting point for users that want to adopt Nix in their project.
I was introduced to the
todomvc-nix repository by zimbatm about 2 years ago, June 26, 2018, to be precise. At that time, I was in the middle of learning Haskell and Nix. As a newcomer, it is hard to find a simple Haskell project example that build using Nix. There are plenty tutorials on using Nix to develop Haskell, though almost all of them are very opinionated to the repository owner and not too beginner-friendly. Hence, as a beginner of both Haskell and Nix, I found it very difficult to read and implement such example to a simple project that I wanted to create.
Because of this complexity and my limited knowledge of Nix, I never managed to implement one Haskell project using it. This is very different with
todomvc-nix, because it is very simple and easy to understand. However,
In 2020, I had the idea to upgrade the
todomvc-nix in terms of implementation of programming languages, databases, and CI/CD. Since I have been working with zimbatm for several times, especially on open source projects, I proposed this and the refreshment was carried out for approximately 3-4 weeks. Thus, once again, Numtide agreed to let me do the refreshment on a part-time basis (a maximum of 4 hours/day) to refresh the
As previously explained,
todomvc-nix is a repository for showing how to manage both the development and production environment of the project made in any programming language using Nix. We use TodoMVC project as an example because it provides various programming languages implementation for a TODO application.
-nix added behind the
todomvc, it means that this project is built specifically for a Nix based project. It should be noted that in this project, the use of Nix is not only for managing programming language tools (compiler, package management, etc.), but also for managing other related devices in a project, such as databases, containers, scripts, web server, and so on.
todomvc-nix, I try to cover everything that is related to any real-world project managed by Nix.
Before the update, I noticed that
todomvc-nix was good enough for Nix newcomer to learn how to implement Nix in the project. Unfortunately, there are several things that I think need more exploration, such as:
- Programming languages used in the old
- There is no example on database implementations which is very common in an application;
- The CI/CD implementation on Nix is confusing;
- Lags behind in recent Nix language development (especially the flakes feature)
Accordingly, I am determined to make an update so that every Nix newcomer can easily use Nix, with its up to date feature, to develop their project using their programming language choice.
Implemented full-stack monolith project for the Rust and Haskell programming languages
The first thing that I want to have in
todomvc-nix is to show a full-stack project for every existing programming language. Currently, I only familiar with Haskell and Rust, so I try to make an example using these languages. The good news is, it is possible to implement full-stack web application in both Haskell and Rust!
I will not go into more detail on every decision about libraries I used for each Haskell and Rust in this article because it will make the writing very long and tend to be unfocused.
Haskell development using Nix can be done in 2 ways, namely: 1) using the default
haskellPackages from Nix; or 2) using the
haskell.nix developed by HK Input-Output. Another way is to use the built-in
nixpkgs provided by libraries that already using Nix (e.g. reflex-dom and miso).
The libraries that I use are not really important or affect the Nix in any ways. I chose these libraries just to challenge myself. For the backend, I use the servant, polysemy, and postgresql-simple. These three libraries are sufficient as the basis for creating TodoMVC application, while the other libraries are very commonly used among haskellers (e.g.
For the frontend, I use miso, a library that uses
reflex (one of the libraries that I am very familiar and happy with) due to several things which will be explained in the future post.
Rust is the language that I have used the most since Numtide hired me. I love this language because for Haskeller like me, the concepts that Rust presents are very easy to digest and understand.
For the frontend side, I use the
Implementation of the PostgreSQL database backend
I choose PostgreSQL as a database for
todomvc-nix because I was inspired by the postgresql's configuration in the deckdeckgo project that built using Nix. I learned a lot from the repository on how to setup a postgresql development environment using Nix.
For database migration, I use
sqitch because I never use the built-in database migration tool from libraries in either Haskell or Rust. In my opinion, sqitch is sufficient for my needs in terms of database migration. Through this database implementation,
todomvc-nix can provide an example of using
wrapProgram in Nix code.
Using Flake as Nix's newest feature
Flake is a new feature from Nix which aims to improve reproducibility, composability, and usability of a project that uses the Nix ecosystem. Even though it hasn't even shipped to a stable release of Nix yet, I feel it's a good time to refreshed the
todomvc-nix project by implementing the flakes feature as it's close to being released in beta. The important part of this refreshment is that a non-flake-nix users don't have to switch to flake immediately and can use the old
nix-shell commands. Yes, the flake feature needs to be activated first as follows:
$ nix-shell -I nixpkgs=channel:nixos-20.03 --packages nixFlakes
Enable experimental features in file
experimental-features = nix-command flakes
For more information please refer to the README in the
This upgrade is very important in my opinion because when I started learning Nix, I was very confused about how to use Nix in a simple project. Therefore, as early as possible, when the flakes feature came out, I need to make an example so that Nix beginner or users who don't understand about the flakes feature can understand the feature as soon as possible.
Restructuring the project hierarchy
Another major refresh of the
todomvc-nix is about the project structure. I put all of the
.nix files into one folder called
nix. This is intended to make maintenance and management of project easier to update. In common practice, each project has one
default.nix and sometimes
shell.nix. So, I make a clear separation in the
todomvc-nix folder hierarchy from the start by grouping all of the
.nix files into its own
My restructuring was actually just separating the smallest part of the todomvc project written in Haskell and Rust into individual folder and having one file
default.nix in it. This is intended so that whenever the project need to be updated, user can just look into the
For the programming language itself, I separate each language into its respective folder, such as Haskell folder will consists of
common folder. This the same for Rust and maybe when adding another programming language in the future.
How to Use todomvc-nix
Although the purpose of
todomvc-nix is to show how flakes feature works in the Nix project, it still possible to be used by Nix users who don't want to use flakes yet.
Nix users without Flake
For users who haven't activated the
Flake feature, they can immediately use
$ nix-build -A defaultNix.legacyPackages.x86_64-linux.nix.haskellBackend
Please refer to the file
default.nix for the
nix-build command and
shell.nix for the
It is possible to use the
nix-shell commands on
todomvc-nix because we use flake-compat.
flake.nix on a project root directory. The
defaultNix attribute on the
flake-compat is a starting point derivation and act like common
devShell attribute will be used.
Nix users with Flake
Users who have enabled the
Flake feature can run the
nix build command to run the
nix develop to enter the shell environment in Nix, and to create a specific project, the user can run:
$ nix build .#rust-backend
$ nix build .#nix.haskellBackend
For the last command, the
# means the location of the folder that has
haskellBackend are the attribute names that are sourced from the
packages attribute in
Check it out!!
At the moment, the project only covers Haskell, and Rust as the example languages, and I hope to add more over time (with your help!). Through this post, I invite all Nix users to check the todomvc-nix repo. It will be an honor if you would contribute in developing
todomvc-nix through programming languages or technologies that you like.
todomvc-nix project is not a de facto way for developing applications using Nix, but it should at least provide a sufficient overview for users to start projects using Nix.