697 stories
·
1 follower

Any Nix package, live in your browser

1 Share

tl;dr Try it at https://trynix.dev. Click hello, or python 3.6.2 from 2017, or two eras of hello at once, or a package that exists in no public cache. A Linux machine boots in the tab and you get a shell with those Nix packages on PATH.

This is my magnus opus of Nix work.

I knew all the ideas I have been creating were building blogs for something greater: nixpkgs-multiverse indexed every version of every package nixpkgs ever shipped, grail taught it version ranges and omniflake allowed adding over sixteen thousand flakes from a single input.

The crazy insight I had lately was the craziness of the “fast-mode” of the nixmultiverse.com, which lets you skip evaluation and go straight to the store path. This lets you leverage the amazingness of Nix without having to deal with the complexity of evaluation and building. You can just ask for a package and get the exact store path that Hydra built for it, at any version it ever had.

If we have the produced binaries, we can run them. And if we can run them, we can run any of them, in a browser tab, with nothing installed on the host machine.

Welcome to trynix, a browser-based Nix package runner. You can browse the complete history of nixpkgs, over 310,083 package versions, and run any of them1 in a Linux machine that boots in your tab. It is a Nix store in memory, a Linux kernel in WebAssembly, and a terminal emulator in the page.

This is bonkers! 🤯 We can boot the VM with the store-path closure within seconds. Nothing is pre-installed: search, pick a version, boot, run it.

The craziest part? We are not restricted to the public cache. You can share a store path you built yourself, and anyone can boot it in their browser tab. The only requirement is that the cache is served with access-control-allow-origin: *, which GitHub Pages does for free2, so does Cachix and obviously cache.nixos.org as well.

In a unbelievable twist of fate, I had actually requested 5 years ago for cache.nixos.org to serve access-control-allow-origin: * via issue#156 to make it possible to query the cache from an OpenAPI specification I had implemented. Thank you universe. 🙏

This link boots a VM with a store-path served from Github Pages of a modified GNU hello. This is a store path that does not exist on cache.nixos.org and yet it boots in your browser tab.

alt text

Making the pieces fit

Since we can access store-paths from caches that serve access-control-allow-origin: *, that makes the browser a legitimate Nix client.

The missing piece the browser lacked was somewhere to run the binaries since they store-paths are either x86-64 or aarch64 ELF executables.

Standing on the shoulders of giants, we can run a Linux kernel in WebAssembly. This means we can boot a real x86_64 kernel inside our browser tab. Give that kernel a filesystem containing a Nix store. All that’s left knowing which store-paths to fetch, which we beautifully solved with nixpkgs-multiverse. 🤌

digraph trynix {
  rankdir=LR;
  fontname="Helvetica";
  node [fontname="Helvetica", fontsize=10, shape=rect,
        style="filled,rounded", color="#4C78A8", fillcolor="#DCE6F1"];
  edge [fontname="Helvetica", fontsize=9, color="#666666", arrowsize=0.7];
  nodesep=0.35; ranksep=0.55; pad=0.3;

  subgraph cluster_browser {
    label="your browser tab";
    fontsize=10;
    color="#bbbbbb";
    style=rounded;

    page [label="the page"];
    store [label="nix store\nin memory", fillcolor="#E8F0E3", color="#4f8a6b"];
    vm [label="qemu-wasm\nx86_64 Linux", fillcolor="#F3E6DE", color="#9e3413"];
    term [label="your shell"];
  }

  mv [label="nixpkgs-multiverse\nattr + version → store path", fillcolor="#EFE6F5", color="#8a5fa8"];
  cache [label="cache.nixos.org\nnarinfo + NARs", fillcolor="#EFE6F5", color="#8a5fa8"];

  page -> mv [label="which path?"];
  page -> cache [label="closure"];
  cache -> store [label="unpacked"];
  store -> vm [label="9p"];
  vm -> term;
}

I have to keep reminding myself: there is no server in the above picture, the web-page is purely static files and everything else is a publicly accessible cache. It is a virtual machine that exists only inside your tab. The ultimate embodiment of Erase your darlings.

Since this is Nix, we get the simplicity of managing multiple versions of the same package. You can boot two versions of hello in one machine, and they will not conflict because each binary names its own dependencies by absolute path (RUNPATH) down to the loader and libc.

Once the VM is already started, you can add more store-paths to it while it’s running. This is no different than adding more paths to your own /nix/store on your laptop. No reboot, or dnf install, or apt-get install, the site fetches the closure and adds it to the store.

It has to feel instant

Booting a kernel under emulation is slow, and despite the amazingness of the idea, no one would use it if it took 30 seconds to get a shell.

The site employs some neat tricks to make it feel instant. The site pre-fetches the engine and the VM snapshot in the background, so by the time you click a link, you have already downloaded it.

The site also never boots the VM from scratch. It resumes. A machine is booted once, ahead of time, on a native build of the same QEMU, and paused at the moment before it mounts the store which is then saved to a snapshot.

Subsequent visits to the site have the engine and snapshot already in the browser cache, so the only thing that has to be fetched is the closure of the store-path you asked for. This makes each subsequent visit feel much faster.

import pandas as pd
from plotnine import *

# Measured 2026-09-05 against trynix.dev in headless Chromium on a
# Ryzen 7 7840U: three visits per package with a fresh browser profile,
# then a reload with everything already cached. Medians. The clock runs
# from opening the link to a prompt you can type at.
df = pd.DataFrame({
    "package": ["hello", "hello", "ripgrep", "ripgrep", "python3", "python3"],
    "visit": ["first visit", "revisit", "first visit", "revisit",
              "first visit", "revisit"],
    "seconds": [4.2, 1.5, 4.3, 1.7, 7.5, 3.5],
})
df["package"] = pd.Categorical(
    df["package"], categories=["python3", "ripgrep", "hello"], ordered=True
)
df["visit"] = pd.Categorical(
    df["visit"], categories=["first visit", "revisit"], ordered=True
)
df["label_at"] = df["seconds"] + 0.15

plot = (
    ggplot(df, aes("package", "seconds", fill="visit"))
    + geom_col(position=position_dodge(width=0.75), width=0.65)
    + geom_text(
        aes(y="label_at", label="seconds"),
        position=position_dodge(width=0.75),
        ha="left",
        size=8,
    )
    + coord_flip()
    + scale_fill_manual(values=["#4C78A8", "#A8C7E5"], name="")
    + labs(x="", y="seconds to a shell")
    + theme(figure_size=(6.5, 2.8), legend_position="top")
)

I have to give a lot of credit to LLMs here for helping find a lot of the performance opportunities and bottlenecks. What first started as a “neat idea” turned into an incredibly usable project with their help.

Despite all the performance work, it is still not instant. It is fast enough to be usable, but it is not instant. Execution of a binary is still slow, because it is running under emulation. The first time you run a binary, it is translated from x86_64 to WebAssembly and that takes time. Subsequent runs are faster, because the translation is cached in memory.

Lastly, we have an upper-bound on the size of the closure we can fetch. The whole closure has to fit in tab memory, which is set to a hard limit of ~1.5GiB as of now and WebAssembly has a hard limit of 4GiB as it is a 32-bit address space.

More than a parlor trick

The demo is clearly fun and impressive, but is it more than a parlor trick? I have been thinking of endless ideas of ways in which this could be a new way to use and leverage Nix.

Reviewing a pull request by using the software. If your CI already pushes to a cache, like Cachix, and if you use Nix, then a PR has produced real artifacts by the time a human looks at it. A bot can leave a link that boots exactly those artifacts. The reviewer does not clone, does not build, does not trust a screenshot. They click, and can immediately test out the software. “Does this fix the bug?” stops being a thought experiment.

Agent Artifacts. Agents can produce Nix store paths as artifacts, and those artifacts can be shared with humans or other agents. A bot can produce a store path, and another bot can boot it in a browser tab and run tests against it.

Bug reports that carry their own environment. “Works on my machine” is a URL now for reproduction.

Documentation you can run. A tutorial that names a tool version can link a shell with that exact version on PATH, pinned forever, with no install step standing between a reader and the first command.

Archaeology. You can run historic versions of software and explore their behavior. You can run a version of Python from 2017 and see what it does, or a version of hello from 2005 and see how it differs from today. This was already possible with Nix, but now you can do it in the browser.

The source is at github.com/fzakaria/trynix. The Nix cache has quietly served an open CORS header for years, waiting to be abused used. Go boot something old.

  1. It is a serial console, so nothing graphical. The machine boots to a shell, and you can run any command-line program in the store. 

  2. I was a little surprised to learn that GitHub Pages can work as a binary cache. It is just a static file server, and it serves access-control-allow-origin: * on every file. That is all that is needed to make a Nix store path available to trynix

Read the whole story
PhaChayFy
37 minutes ago
reply
Australia
Share this story
Delete

s'more cookie

1 Share

allosexual:

Read the whole story
PhaChayFy
5 days ago
reply
Australia
Share this story
Delete

when in fics they say two characters gave each other a look this is always what i envision in my…

1 Share

nextstopparis:

when in fics they say two characters gave each other a look this is always what i envision in my head

Read the whole story
PhaChayFy
5 days ago
reply
Australia
Share this story
Delete

Driving PSA

1 Comment and 5 Shares
This PSA brought to you by several would-be assassins who tried to wave me in front of speeding cars in the last month and who will have to try harder next time.
Read the whole story
PhaChayFy
14 days ago
reply
Australia
Share this story
Delete
1 public comment
fxer
844 days ago
reply
This is a pet peeve at 4-way stops where the person whose turn to go waves someone else thru…and basically succeeds in slowing everyone down with the resulting confusion: “me? You? Me?” Gas. Brake. “Oh you? Me?”

Everyone knows the rules and simply following them is the quickest way to get everyone through the stop
Bend, Oregon
beejjorgensen
844 days ago
When I'm on a bicycle, people in a roundabout will illegally stop and let me enter it. Some time I'm just going to wave back until they go. :)
Vixy
844 days ago
I literally got hit this way. Little did I suspect the assassination conspiracy!
newsome
844 days ago
My favorite driving expression - "Don't be polite, be predictable." (2nd favorite - "The right of way is not yours to give.")
silberbaer
842 days ago
They think they're being nice, but really they're being an asshole. Although the assassin theory also sounds reasonable, I just don't generally think any random stranger is that smart, nor am I that important.
jimwise
822 days ago
You're not. Your great-great-great-grandkid tho? *Super* important.

Doctor: $140,000 a year

1 Share

raevenlywrites:

worldheritagepostorganization:

kolbye:

hokuto-ju-no-ken:

pukicho:

bog-dweller-official:

pukicho:

boob-a-chu:

trilllizard420:

pukicho:

trilllizard420:

pukicho:

Doctor: $140,000 a year

Furry artist on Patreon: $160,000 a year

i think you’re lowballing the furry art amount tbh

I’m sorry for the inaccuracies, Doctor Yiff

no matter how I respond to this I don’t look good, well played. i walked right into that

Well, furry artists are typically more competent and courteous than your average doctor, so I can see that.

Did you just legitimately tell me that a person who draws wolf ass is more competent than a dude who spent 8+ years in a university to give you your lung transplant?

doctors are bullshit and furry artists perform an infinitely more valuable service to society compared to them

You will die in 7 days

It took doctor’s like 10 years to diagnose what was wrong with me, some insisting I was faking for attention while a furry artist I knew just went “that sounds like crohn’s” after hearing me complain once and ended up being right

Also I can’t go to a doctor and ask them to draw Rouge the Bat wider than she is tall with tits to match, now can I

You could if you weren’t a fucking coward

World Heritage Post

Art by coolfrogdude together at last

Read the whole story
PhaChayFy
14 days ago
reply
Australia
Share this story
Delete

knowlesian:knowlesian:knowlesian:“why do i believe this” and “who benefits from me believing it” are...

1 Share

knowlesian:

knowlesian:

knowlesian:

“why do i believe this” and “who benefits from me believing it” are the first steps to decolonization and we should all be doing this more

since this is on my dash again another two steps, a little harder this time

“who do i hurt when i do this?” and “could i look them in the eye, validate and acknowledge that hurt, and then keep doing it anyway?”

feels like a good day for another two.

“whose voice is missing from this story” and then “how do i seek out those voices/how does a story i think i know change when i add new perspectives”

Read the whole story
PhaChayFy
14 days ago
reply
Australia
Share this story
Delete
Next Page of Stories