
This blog post is based on a product presentation by Jérôme Andrieux, VP of Strategic Operations, at SymfonyCon 2023 about Upsun's experience with Nix. We utilized ChatGPT for transcription and to enhance the grammar and syntax.
Managing containers at scale is no joke. When you're running a platform that needs to support dozens of programming languages, multiple versions of each, and countless combinations of dependencies, traditional container management quickly becomes a nightmare. This is the story of how Upsun discovered an elegant solution to what many consider an unsolvable problem.
Jérôme, a product manager at Upsun, recently shared their infrastructure challenges at a developer conference. The numbers are staggering: Upsun maintains 166 different container images just to support their platform-as-a-service offering.
Here's the breakdown:
This massive undertaking requires three full-time engineers who, in Jérôme's words, are "freaking good at this." But even with talented teams, maintaining this many images is exhausting and error-prone.
The real challenge isn't just the number of images. It's the dependency conflicts that arise when trying to support diverse application needs. Jérôme illustrated this with a relatable scenario:
Imagine you need:
Try installing all of these together on a traditional system, and you'll quickly find yourself in what developers call "dependency hell." Different packages need different versions of the same underlying libraries, creating conflicts that are nearly impossible to resolve.
Jérôme shared a real example from Upsun's experience: When PHP 8.2 was released, they wanted to upgrade the Symfony.com website. The upgrade broke because their documentation generation tool required Python 2.7, but the new PHP 8.2 image was built on a newer Debian version that had dropped Python 2.7 support entirely.
This led to the familiar XKCD scenario: "I'm maintaining a huge chain of technology solely to support itself."
The solution Upsun discovered is Nix, a functional package manager that approaches dependency management in a completely different way from traditional systems.
Nix treats packages as immutable values in a functional programming sense. Every package is built in complete isolation with these key principles:
/nix/store/ with paths that include their unique hash. This means you can have multiple versions of the same software installed simultaneously without conflicts.With Nix, when Jérôme says "it works on my machine," he can actually guarantee it will work on yours too. The functional approach ensures that if a build succeeds once, it will succeed identically anywhere else.
During his presentation, Jérôme demonstrated something that would be nearly impossible with traditional package management. Using a simple nix-shell command, he created an environment with:
All are running simultaneously on the same system without conflicts. The demonstration showed how Nix evaluates all the different package expressions and their dependencies, then creates an isolated environment where everything coexists peacefully.
For automation, this can be codified in a simple Nix file:
{
inputs = [
php83
python2
imagemagick6
];
shellHook = ''
echo "Hello Symfony Conference!"
'';
}Run it with:
nix-shellFor Upsun, adopting Nix represents a potential reduction from 166 maintained images to essentially one composable image. Instead of maintaining separate containers for every possible combination of runtime and dependencies, they can use Nix to compose the exact environment needed for each application.
This approach offers several advantages:
While Upsun's scale highlights the problem, most developers encounter similar issues. How many times have you struggled to compile a tool that needs specific library versions, only to give up and reach for Docker instead?
Jérome points out that Docker, while useful, doesn't actually solve dependency hell; it just containers it. You can still run into the same conflicts within your Docker images.
Nix offers a fundamentally different approach. Instead of working around dependency conflicts, it eliminates them through mathematical precision and the principles of functional programming.
A question from the room:
You control that. You can track a channel and move forward with minor updates, or you can pin to a specific commit of Nixpkgs to hold versions steady. You can also pin specific packages. To share with your team, commit your default.nix or shell.nix in the repository. Anyone can run the same build.
Jerome shared what is coming. On Upsun, Nix support is being rolled out as an experimental feature. In your YAML, instead of writing long build hooks, you will be able to declare a Nix stack and packages. The platform will use a Nix image under the hood. Over time, deeper customization with Nix expressions may follow.
Nix isn't just for large platforms. Individual developers can use it to:
The Nix ecosystem includes over 80,000 packages, making it one of the largest package repositories in the world. Everything is built from source by default, with pre-built binaries available for common configurations.
Upsun is integrating Nix directly into their platform, allowing developers to specify their dependencies functionally rather than choosing from pre-built images. This will be launched as an experimental feature in the coming weeks.
For the broader developer community, Nix represents a paradigm shift toward more reliable, reproducible software deployment. While it requires learning functional concepts, the payoff in reduced complexity and increased reliability is substantial.
The next time you find yourself struggling with dependency conflicts, remember Jérôme's advice: there's a better way than maintaining "a huge chain of technology solely to support itself." Sometimes the solution isn't to manage complexity, it's to eliminate it.
Join our monthly newsletter
Compliant and validated