{"pdfpcFormat":2,"disableMarkdown":false,"pages":[{"idx":0,"label":"1","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Hello!\n\nWelcome to my talk on learning Nix the fun way.\n\nThis slide deck can be found online at the following link. I welcome improvements, edits and corrections."},{"idx":1,"label":"1","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Great, so before we begin, let me introduce myself.\n\nMy name is Farid Zakaria, and I'm a software engineer at Meta.\n\nI've been using Nix in various capacities for quite a while now. I've presented at a few previous incarnations of Nix conventions, and I've had the pleasure of bringing Nix into many of the companies I've worked at, including Confluent and Google.\n\nI'm very bullish on Nix and it has been a source of mostly joy, and it was additionally the inspiration for a lot of my PhD research."},{"idx":2,"label":"2","overlay":0,"forcedOverlay":false,"hidden":false,"note":"I have given Nix talks a few times, individually and to groups -- including to engineering groups. I've noticed that explaining the rationale for Nix, and even Nix itself, is challenging. It's an active area of discussion within the community.\n\nEven reflecting on my own journey of learning and loving Nix, it took a few iterations, so I'm pretty empathetic to those that feel they might not understand what the big deal is or find it too complex.\n\nSo the disclaimer is that some of what I demonstrate may be complicated or tough to understand. What I do hope to convey however is that there is a reason for this complexity. Software is complex, and aiming for the levels of guarantees that Nix provides puts you face to face with that complexity.\n\nPlease feel free to ask me questions during the talk. I have kept the slides light on written text, but there are snapshots of code. I have all of the code handy, and if it's helpful I'm willing to DO IT LIVE and go beyond what is shown."},{"idx":3,"label":"3","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Okay, so this is the alternate working title for this talk.\n\nI want to share why I love Nix. Nix has brought a lot of joy and simplification to my software life, and oftentimes learning it can feel challenging without much insight into what is the purpose."},{"idx":4,"label":"4","overlay":0,"forcedOverlay":false,"hidden":false,"note":"I've given a lot of talks about Nix. I've given talks to meetup groups, friends and plenty internally at the companies I've worked at.\n\nThis is how I've always pictured myself giving a talk about Nix.\n\nIt's always a noble pursuit where I impart the beautiful knowledge of that which is Nix.\n\n** click **\n\nI tend to always begin these talks at the beginning, by discussing Eelco's PhD, The Purely Functional Software Deployment Model, where he first shared Nix with the world in 2006."},{"idx":5,"label":"4","overlay":1,"forcedOverlay":true,"hidden":false,"note":"I've given a lot of talks about Nix. I've given talks to meetup groups, friends and plenty internally at the companies I've worked at.\n\nThis is how I've always pictured myself giving a talk about Nix.\n\nIt's always a noble pursuit where I impart the beautiful knowledge of that which is Nix.\n\n** click **\n\nI tend to always begin these talks at the beginning, by discussing Eelco's PhD, The Purely Functional Software Deployment Model, where he first shared Nix with the world in 2006."},{"idx":6,"label":"5","overlay":0,"forcedOverlay":false,"hidden":false,"note":"In retrospect, this slide better depicts how the talks have gone. People in attendance are at best totally bored by the nuance and complexity of what I'm discussing.\n\n** click **\n\nAt worst, I've immediately turned off potential new Nix-enthusiasts by jumping straight into academic and dense vocabulary about the ideas and technology that powers Nix."},{"idx":7,"label":"5","overlay":1,"forcedOverlay":true,"hidden":false,"note":"In retrospect, this slide better depicts how the talks have gone. People in attendance are at best totally bored by the nuance and complexity of what I'm discussing.\n\n** click **\n\nAt worst, I've immediately turned off potential new Nix-enthusiasts by jumping straight into academic and dense vocabulary about the ideas and technology that powers Nix."},{"idx":8,"label":"6","overlay":0,"forcedOverlay":false,"hidden":false,"note":"The motivation of this talk is to do it different this time.\n\n** click **\n\nI want to impart the benefits of using Nix by what I believe to be learning Nix the fun way."},{"idx":9,"label":"6","overlay":1,"forcedOverlay":true,"hidden":false,"note":"The motivation of this talk is to do it different this time.\n\n** click **\n\nI want to impart the benefits of using Nix by what I believe to be learning Nix the fun way."},{"idx":10,"label":"7","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Let's begin with something seemingly innocuous. Here is a small script to determine the IP of your current machine.\n\nThis should look pretty standard, I'm hoping, to most people, and probably reminiscent of a lot of scripts we might have written ourselves that stitch a few programs together.\n\n** click **\n\nAnd it does what it says."},{"idx":11,"label":"7","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Let's begin with something seemingly innocuous. Here is a small script to determine the IP of your current machine.\n\nThis should look pretty standard, I'm hoping, to most people, and probably reminiscent of a lot of scripts we might have written ourselves that stitch a few programs together.\n\n** click **\n\nAnd it does what it says."},{"idx":12,"label":"8","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Here is what rewriting that same script in the most raw form of Nix might look like.\n\nI know I just showed you a new language, but for a tiny second just suspend questions you may have. The only take-away from the language would be that it looks semi-similar to other languages you may have used; it has a somewhat JSON-like feel to it.\n\n** click **\n\nHere is the important part of this Nix recipe, and it looks similar-ish to what we had before."},{"idx":13,"label":"8","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Here is what rewriting that same script in the most raw form of Nix might look like.\n\nI know I just showed you a new language, but for a tiny second just suspend questions you may have. The only take-away from the language would be that it looks semi-similar to other languages you may have used; it has a somewhat JSON-like feel to it.\n\n** click **\n\nHere is the important part of this Nix recipe, and it looks similar-ish to what we had before."},{"idx":14,"label":"9","overlay":0,"forcedOverlay":false,"hidden":false,"note":"But of course, this is not what you'd actually write in Nix. The following is a little more idiomatic and a lot more terse.\n\nHere it much more resembles the original script.\n\n** click **\n\nFor those that might want to follow along now or later, it's important to keep note of this commit value, and that I'm building this on an amd64 Linux machine."},{"idx":15,"label":"9","overlay":1,"forcedOverlay":true,"hidden":false,"note":"But of course, this is not what you'd actually write in Nix. The following is a little more idiomatic and a lot more terse.\n\nHere it much more resembles the original script.\n\n** click **\n\nFor those that might want to follow along now or later, it's important to keep note of this commit value, and that I'm building this on an amd64 Linux machine."},{"idx":16,"label":"9","overlay":2,"forcedOverlay":true,"hidden":false,"note":"But of course, this is not what you'd actually write in Nix. The following is a little more idiomatic and a lot more terse.\n\nHere it much more resembles the original script.\n\n** click **\n\nFor those that might want to follow along now or later, it's important to keep note of this commit value, and that I'm building this on an amd64 Linux machine."},{"idx":17,"label":"10","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Let's build it!\n\n** click **\n\nWe get some output path, okay cool.\n\n** click **\n\nThat output path has the script we created.\n\n** click **\n\nWe can execute that script and it works as expected."},{"idx":18,"label":"10","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Let's build it!\n\n** click **\n\nWe get some output path, okay cool.\n\n** click **\n\nThat output path has the script we created.\n\n** click **\n\nWe can execute that script and it works as expected."},{"idx":19,"label":"10","overlay":2,"forcedOverlay":true,"hidden":false,"note":"Let's build it!\n\n** click **\n\nWe get some output path, okay cool.\n\n** click **\n\nThat output path has the script we created.\n\n** click **\n\nWe can execute that script and it works as expected."},{"idx":20,"label":"10","overlay":3,"forcedOverlay":true,"hidden":false,"note":"Let's build it!\n\n** click **\n\nWe get some output path, okay cool.\n\n** click **\n\nThat output path has the script we created.\n\n** click **\n\nWe can execute that script and it works as expected."},{"idx":21,"label":"11","overlay":0,"forcedOverlay":false,"hidden":false,"note":"What is the script we produced though? Why did we need Nix?\n\n** click **\n\nThe output of our script looks very similar now to the original variant we had before, except everything seems to be prefixed with some long string."},{"idx":22,"label":"11","overlay":1,"forcedOverlay":true,"hidden":false,"note":"What is the script we produced though? Why did we need Nix?\n\n** click **\n\nThe output of our script looks very similar now to the original variant we had before, except everything seems to be prefixed with some long string."},{"idx":23,"label":"12","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Although I promised not to go too academic into Nix, this part is important.\n\n** click **\n\nWhat is that long prefix string ahead of our built script, and similarly found within the script before each of the tools?\n\n** click **\n\nThere's a handy Nix command to show us the meaning of that prefix."},{"idx":24,"label":"12","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Although I promised not to go too academic into Nix, this part is important.\n\n** click **\n\nWhat is that long prefix string ahead of our built script, and similarly found within the script before each of the tools?\n\n** click **\n\nThere's a handy Nix command to show us the meaning of that prefix."},{"idx":25,"label":"12","overlay":2,"forcedOverlay":true,"hidden":false,"note":"Although I promised not to go too academic into Nix, this part is important.\n\n** click **\n\nWhat is that long prefix string ahead of our built script, and similarly found within the script before each of the tools?\n\n** click **\n\nThere's a handy Nix command to show us the meaning of that prefix."},{"idx":26,"label":"13","overlay":0,"forcedOverlay":false,"hidden":false,"note":"The whole purpose of Nix is to kind of build this file. This is the recipe describing what it takes to build our IP script.\n\n** click **\n\nIt has a build command.\n\n** click **\n\nThe text of our script, which may also be the source code if it's a little more involved.\n\n** click **\n\nThe tools we depend on to make the script function, like cURL and jq.\n\n** click **\n\nThe system we're running on, since Nix also supports different architectures and operating systems.\n\n** click **\n\nAll of this information is hashed to calculate this prefix.\n\nThere's a really mind-bending property though."},{"idx":27,"label":"13","overlay":1,"forcedOverlay":true,"hidden":false,"note":"The whole purpose of Nix is to kind of build this file. This is the recipe describing what it takes to build our IP script.\n\n** click **\n\nIt has a build command.\n\n** click **\n\nThe text of our script, which may also be the source code if it's a little more involved.\n\n** click **\n\nThe tools we depend on to make the script function, like cURL and jq.\n\n** click **\n\nThe system we're running on, since Nix also supports different architectures and operating systems.\n\n** click **\n\nAll of this information is hashed to calculate this prefix.\n\nThere's a really mind-bending property though."},{"idx":28,"label":"13","overlay":2,"forcedOverlay":true,"hidden":false,"note":"The whole purpose of Nix is to kind of build this file. This is the recipe describing what it takes to build our IP script.\n\n** click **\n\nIt has a build command.\n\n** click **\n\nThe text of our script, which may also be the source code if it's a little more involved.\n\n** click **\n\nThe tools we depend on to make the script function, like cURL and jq.\n\n** click **\n\nThe system we're running on, since Nix also supports different architectures and operating systems.\n\n** click **\n\nAll of this information is hashed to calculate this prefix.\n\nThere's a really mind-bending property though."},{"idx":29,"label":"13","overlay":3,"forcedOverlay":true,"hidden":false,"note":"The whole purpose of Nix is to kind of build this file. This is the recipe describing what it takes to build our IP script.\n\n** click **\n\nIt has a build command.\n\n** click **\n\nThe text of our script, which may also be the source code if it's a little more involved.\n\n** click **\n\nThe tools we depend on to make the script function, like cURL and jq.\n\n** click **\n\nThe system we're running on, since Nix also supports different architectures and operating systems.\n\n** click **\n\nAll of this information is hashed to calculate this prefix.\n\nThere's a really mind-bending property though."},{"idx":30,"label":"13","overlay":4,"forcedOverlay":true,"hidden":false,"note":"The whole purpose of Nix is to kind of build this file. This is the recipe describing what it takes to build our IP script.\n\n** click **\n\nIt has a build command.\n\n** click **\n\nThe text of our script, which may also be the source code if it's a little more involved.\n\n** click **\n\nThe tools we depend on to make the script function, like cURL and jq.\n\n** click **\n\nThe system we're running on, since Nix also supports different architectures and operating systems.\n\n** click **\n\nAll of this information is hashed to calculate this prefix.\n\nThere's a really mind-bending property though."},{"idx":31,"label":"13","overlay":5,"forcedOverlay":true,"hidden":false,"note":"The whole purpose of Nix is to kind of build this file. This is the recipe describing what it takes to build our IP script.\n\n** click **\n\nIt has a build command.\n\n** click **\n\nThe text of our script, which may also be the source code if it's a little more involved.\n\n** click **\n\nThe tools we depend on to make the script function, like cURL and jq.\n\n** click **\n\nThe system we're running on, since Nix also supports different architectures and operating systems.\n\n** click **\n\nAll of this information is hashed to calculate this prefix.\n\nThere's a really mind-bending property though."},{"idx":32,"label":"14","overlay":0,"forcedOverlay":false,"hidden":false,"note":"That recipe earlier contained the tools we needed, and the source code; each one also had a unique hash prefix.\n\nThere's a level of recursion here that means repeatedly seeing this hash is an incredibly strong property of reproducibility.\n\nIt means not only was our script text the same and tool dependencies the same, but the same applies to each tool itself and so forth."},{"idx":33,"label":"15","overlay":0,"forcedOverlay":false,"hidden":false,"note":"In Nix, you spend considerable time wiring things up, and the purpose is to completely model your software as a graph.\n\nTurns out that once you have a graph, everything you might want to do in software is a permutation or transformation on the graph.\n\nHere we have the full dependency graph of our seemingly innocuous script. It's a little more involved than originally thought."},{"idx":34,"label":"16","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Okay, here is another Nix snippet. Again ignore the actual syntax, but know that what we are defining here is a shell environment.\n\n** click **\n\nWe import our same script and add it to the packages that we want present in our shell."},{"idx":35,"label":"16","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Okay, here is another Nix snippet. Again ignore the actual syntax, but know that what we are defining here is a shell environment.\n\n** click **\n\nWe import our same script and add it to the packages that we want present in our shell."},{"idx":36,"label":"16","overlay":2,"forcedOverlay":true,"hidden":false,"note":"Okay, here is another Nix snippet. Again ignore the actual syntax, but know that what we are defining here is a shell environment.\n\n** click **\n\nWe import our same script and add it to the packages that we want present in our shell."},{"idx":37,"label":"17","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Let's enter the shell.\n\n** click **\n\nWe see the shell hook we wrote. That's just an aid to demonstrate we entered the shell.\n\n** click ** ** click **\n\nMy PATH now contains what-is-my-ip, and importantly at the exact same hash prefix string we've built before.\n\n** click **\n\nThe script also works and runs as we expect."},{"idx":38,"label":"17","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Let's enter the shell.\n\n** click **\n\nWe see the shell hook we wrote. That's just an aid to demonstrate we entered the shell.\n\n** click ** ** click **\n\nMy PATH now contains what-is-my-ip, and importantly at the exact same hash prefix string we've built before.\n\n** click **\n\nThe script also works and runs as we expect."},{"idx":39,"label":"17","overlay":2,"forcedOverlay":true,"hidden":false,"note":"Let's enter the shell.\n\n** click **\n\nWe see the shell hook we wrote. That's just an aid to demonstrate we entered the shell.\n\n** click ** ** click **\n\nMy PATH now contains what-is-my-ip, and importantly at the exact same hash prefix string we've built before.\n\n** click **\n\nThe script also works and runs as we expect."},{"idx":40,"label":"17","overlay":3,"forcedOverlay":true,"hidden":false,"note":"Let's enter the shell.\n\n** click **\n\nWe see the shell hook we wrote. That's just an aid to demonstrate we entered the shell.\n\n** click ** ** click **\n\nMy PATH now contains what-is-my-ip, and importantly at the exact same hash prefix string we've built before.\n\n** click **\n\nThe script also works and runs as we expect."},{"idx":41,"label":"17","overlay":4,"forcedOverlay":true,"hidden":false,"note":"Let's enter the shell.\n\n** click **\n\nWe see the shell hook we wrote. That's just an aid to demonstrate we entered the shell.\n\n** click ** ** click **\n\nMy PATH now contains what-is-my-ip, and importantly at the exact same hash prefix string we've built before.\n\n** click **\n\nThe script also works and runs as we expect."},{"idx":42,"label":"18","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Wow. Do we all realize what we just did?\n\nWe just created a simple way to bring reproducible developer environments to projects.\n\nNo need for containers. No need for namespaces. Easy to enter and easy to validate thanks to that prefix hash."},{"idx":43,"label":"19","overlay":0,"forcedOverlay":false,"hidden":false,"note":"We actually know everything about our code now.\n\n** click **\n\nBecause we know the full dependency closure, we can do binary or source deployments.\n\n** click **\n\nWe simply copy the necessary store paths to another machine...\n\n** click **\n\n...and that machine doesn't even need Nix installed.\n\n** click **\n\nProfit."},{"idx":44,"label":"19","overlay":1,"forcedOverlay":true,"hidden":false,"note":"We actually know everything about our code now.\n\n** click **\n\nBecause we know the full dependency closure, we can do binary or source deployments.\n\n** click **\n\nWe simply copy the necessary store paths to another machine...\n\n** click **\n\n...and that machine doesn't even need Nix installed.\n\n** click **\n\nProfit."},{"idx":45,"label":"19","overlay":2,"forcedOverlay":true,"hidden":false,"note":"We actually know everything about our code now.\n\n** click **\n\nBecause we know the full dependency closure, we can do binary or source deployments.\n\n** click **\n\nWe simply copy the necessary store paths to another machine...\n\n** click **\n\n...and that machine doesn't even need Nix installed.\n\n** click **\n\nProfit."},{"idx":46,"label":"19","overlay":3,"forcedOverlay":true,"hidden":false,"note":"We actually know everything about our code now.\n\n** click **\n\nBecause we know the full dependency closure, we can do binary or source deployments.\n\n** click **\n\nWe simply copy the necessary store paths to another machine...\n\n** click **\n\n...and that machine doesn't even need Nix installed.\n\n** click **\n\nProfit."},{"idx":47,"label":"19","overlay":4,"forcedOverlay":true,"hidden":false,"note":"We actually know everything about our code now.\n\n** click **\n\nBecause we know the full dependency closure, we can do binary or source deployments.\n\n** click **\n\nWe simply copy the necessary store paths to another machine...\n\n** click **\n\n...and that machine doesn't even need Nix installed.\n\n** click **\n\nProfit."},{"idx":48,"label":"20","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Here is one such command to copy the graph we saw earlier to another machine. In this example we are leveraging a nix copy command, but you could do something as dumb as scp or rsync.\n\n** click **\n\nThe items are copied over. Now let's login to the machine.\n\n** click **\n\nThe exact store path we want is present there and runs. The fact that it runs means all of its dependencies, who also have hash prefix strings, are also present."},{"idx":49,"label":"20","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Here is one such command to copy the graph we saw earlier to another machine. In this example we are leveraging a nix copy command, but you could do something as dumb as scp or rsync.\n\n** click **\n\nThe items are copied over. Now let's login to the machine.\n\n** click **\n\nThe exact store path we want is present there and runs. The fact that it runs means all of its dependencies, who also have hash prefix strings, are also present."},{"idx":50,"label":"20","overlay":2,"forcedOverlay":true,"hidden":false,"note":"Here is one such command to copy the graph we saw earlier to another machine. In this example we are leveraging a nix copy command, but you could do something as dumb as scp or rsync.\n\n** click **\n\nThe items are copied over. Now let's login to the machine.\n\n** click **\n\nThe exact store path we want is present there and runs. The fact that it runs means all of its dependencies, who also have hash prefix strings, are also present."},{"idx":51,"label":"21","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Wow. We just did a deployment of not only our \"code\", which was our script, but all of its necessary dependencies.\n\nThis blows my mind. I can't tell you the number of times in practice I had to coordinate the runtime needed on the host or some other base library being present."},{"idx":52,"label":"22","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Well, maybe that's a bit aggressive for deployments, and you have already drunk the kool-aid of Kubernetes.\n\n** click **\n\nNo problem! Since we know the graph, everything we'd want is merely a permutation on our graph.\n\nHere is another snippet, and again ignore the syntax, but know this is creating an OCI compliant image.\n\n** click **\n\nWe set the command of the image to be our what-is-my-ip package."},{"idx":53,"label":"22","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Well, maybe that's a bit aggressive for deployments, and you have already drunk the kool-aid of Kubernetes.\n\n** click **\n\nNo problem! Since we know the graph, everything we'd want is merely a permutation on our graph.\n\nHere is another snippet, and again ignore the syntax, but know this is creating an OCI compliant image.\n\n** click **\n\nWe set the command of the image to be our what-is-my-ip package."},{"idx":54,"label":"22","overlay":2,"forcedOverlay":true,"hidden":false,"note":"Well, maybe that's a bit aggressive for deployments, and you have already drunk the kool-aid of Kubernetes.\n\n** click **\n\nNo problem! Since we know the graph, everything we'd want is merely a permutation on our graph.\n\nHere is another snippet, and again ignore the syntax, but know this is creating an OCI compliant image.\n\n** click **\n\nWe set the command of the image to be our what-is-my-ip package."},{"idx":55,"label":"23","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Let's build the image.\n\n** click **\n\nThe output is an OCI tarball.\n\n** click **\n\nWe can load that tarball into the docker daemon as normal.\n\n** click **\n\nRunning the image works as we'd expect as well.\n\n** click **\n\nInspecting the image, we see yet again that same prefix hash on our package for the command to execute -- which continues to give us comfort about the version and state of our software."},{"idx":56,"label":"23","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Let's build the image.\n\n** click **\n\nThe output is an OCI tarball.\n\n** click **\n\nWe can load that tarball into the docker daemon as normal.\n\n** click **\n\nRunning the image works as we'd expect as well.\n\n** click **\n\nInspecting the image, we see yet again that same prefix hash on our package for the command to execute -- which continues to give us comfort about the version and state of our software."},{"idx":57,"label":"23","overlay":2,"forcedOverlay":true,"hidden":false,"note":"Let's build the image.\n\n** click **\n\nThe output is an OCI tarball.\n\n** click **\n\nWe can load that tarball into the docker daemon as normal.\n\n** click **\n\nRunning the image works as we'd expect as well.\n\n** click **\n\nInspecting the image, we see yet again that same prefix hash on our package for the command to execute -- which continues to give us comfort about the version and state of our software."},{"idx":58,"label":"23","overlay":3,"forcedOverlay":true,"hidden":false,"note":"Let's build the image.\n\n** click **\n\nThe output is an OCI tarball.\n\n** click **\n\nWe can load that tarball into the docker daemon as normal.\n\n** click **\n\nRunning the image works as we'd expect as well.\n\n** click **\n\nInspecting the image, we see yet again that same prefix hash on our package for the command to execute -- which continues to give us comfort about the version and state of our software."},{"idx":59,"label":"23","overlay":4,"forcedOverlay":true,"hidden":false,"note":"Let's build the image.\n\n** click **\n\nThe output is an OCI tarball.\n\n** click **\n\nWe can load that tarball into the docker daemon as normal.\n\n** click **\n\nRunning the image works as we'd expect as well.\n\n** click **\n\nInspecting the image, we see yet again that same prefix hash on our package for the command to execute -- which continues to give us comfort about the version and state of our software."},{"idx":60,"label":"24","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Nix and Docker integrate perfectly. The image has exactly the files necessary to run the tool -- effectively distroless.\n\nAnd the same trick works for any deployment format: tarballs, RPMs, debs, AppImages. They are all just another permutation of the graph."},{"idx":61,"label":"25","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Which brings us to the big one. A Linux distribution is simply a collection of packages."},{"idx":62,"label":"26","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Here is a whole NixOS machine described in Nix.\n\n** click **\n\nOur same script, added to the packages for a user named alice.\n\n** click **\n\nAnd we ask for it as a virtual machine."},{"idx":63,"label":"26","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Here is a whole NixOS machine described in Nix.\n\n** click **\n\nOur same script, added to the packages for a user named alice.\n\n** click **\n\nAnd we ask for it as a virtual machine."},{"idx":64,"label":"26","overlay":2,"forcedOverlay":true,"hidden":false,"note":"Here is a whole NixOS machine described in Nix.\n\n** click **\n\nOur same script, added to the packages for a user named alice.\n\n** click **\n\nAnd we ask for it as a virtual machine."},{"idx":65,"label":"26","overlay":3,"forcedOverlay":true,"hidden":false,"note":"Here is a whole NixOS machine described in Nix.\n\n** click **\n\nOur same script, added to the packages for a user named alice.\n\n** click **\n\nAnd we ask for it as a virtual machine."},{"idx":66,"label":"27","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Build it.\n\n** click **\n\nA VM.\n\n** click ** ** click **\n\nBoot it, and log in as alice.\n\n** click **\n\nOur script is on alice's PATH, it resolves to the very same store path, and it runs."},{"idx":67,"label":"27","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Build it.\n\n** click **\n\nA VM.\n\n** click ** ** click **\n\nBoot it, and log in as alice.\n\n** click **\n\nOur script is on alice's PATH, it resolves to the very same store path, and it runs."},{"idx":68,"label":"27","overlay":2,"forcedOverlay":true,"hidden":false,"note":"Build it.\n\n** click **\n\nA VM.\n\n** click ** ** click **\n\nBoot it, and log in as alice.\n\n** click **\n\nOur script is on alice's PATH, it resolves to the very same store path, and it runs."},{"idx":69,"label":"27","overlay":3,"forcedOverlay":true,"hidden":false,"note":"Build it.\n\n** click **\n\nA VM.\n\n** click ** ** click **\n\nBoot it, and log in as alice.\n\n** click **\n\nOur script is on alice's PATH, it resolves to the very same store path, and it runs."},{"idx":70,"label":"27","overlay":4,"forcedOverlay":true,"hidden":false,"note":"Build it.\n\n** click **\n\nA VM.\n\n** click ** ** click **\n\nBoot it, and log in as alice.\n\n** click **\n\nOur script is on alice's PATH, it resolves to the very same store path, and it runs."},{"idx":71,"label":"28","overlay":0,"forcedOverlay":false,"hidden":false,"note":"We've now taken one tiny script and turned it into a developer shell, a deployment, a container and an operating system. So let's step back: what actually is Nix?"},{"idx":72,"label":"29","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Nix is everything, which is part of why it's hard to explain. It began as Eelco Dolstra's PhD research, and I highly recommend the read.\n\nIt's a language, depicted here. It's used ultimately to create what the language refers to as 'derivations', but you can think of them as build recipes. The language resembles JSON a little, with the added bonus that it's a pure, functional, lazy, untyped language. It's kind of like a poor version of Haskell.\n\nIt's also the command line tool itself, called nix, with which I can do a bunch of stuff like build these recipes or create developer environments, as we saw."},{"idx":73,"label":"30","overlay":0,"forcedOverlay":false,"hidden":false,"note":"It's a package collection, known as nixpkgs. On repology's map of every package repository, nixpkgs is out on its own: the largest, and among the freshest.\n\nGitHub publishes a yearly report known as Octoverse, and nixpkgs has been in the top 10 across multiple dimensions such as contributors, activity and pull requests.\n\nAnother fun fact: this whole package set can be bootstrapped from a 357-byte binary seed."},{"idx":74,"label":"31","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Because nixpkgs is a graph, a package is not one thing, it's a recipe you can permute.\n\n** click **\n\nHere's GNU hello, built normally.\n\n** click **\n\nThe same hello, statically linked against musl. One attribute.\n\n** click **\n\nCross-compiled for RISC-V. It won't run on my x86 laptop, which is the point.\n\n** click **\n\nOr for Windows, and we can run it under wine. Same recipe, every time; just a different path through the graph."},{"idx":75,"label":"31","overlay":1,"forcedOverlay":true,"hidden":false,"note":"Because nixpkgs is a graph, a package is not one thing, it's a recipe you can permute.\n\n** click **\n\nHere's GNU hello, built normally.\n\n** click **\n\nThe same hello, statically linked against musl. One attribute.\n\n** click **\n\nCross-compiled for RISC-V. It won't run on my x86 laptop, which is the point.\n\n** click **\n\nOr for Windows, and we can run it under wine. Same recipe, every time; just a different path through the graph."},{"idx":76,"label":"31","overlay":2,"forcedOverlay":true,"hidden":false,"note":"Because nixpkgs is a graph, a package is not one thing, it's a recipe you can permute.\n\n** click **\n\nHere's GNU hello, built normally.\n\n** click **\n\nThe same hello, statically linked against musl. One attribute.\n\n** click **\n\nCross-compiled for RISC-V. It won't run on my x86 laptop, which is the point.\n\n** click **\n\nOr for Windows, and we can run it under wine. Same recipe, every time; just a different path through the graph."},{"idx":77,"label":"31","overlay":3,"forcedOverlay":true,"hidden":false,"note":"Because nixpkgs is a graph, a package is not one thing, it's a recipe you can permute.\n\n** click **\n\nHere's GNU hello, built normally.\n\n** click **\n\nThe same hello, statically linked against musl. One attribute.\n\n** click **\n\nCross-compiled for RISC-V. It won't run on my x86 laptop, which is the point.\n\n** click **\n\nOr for Windows, and we can run it under wine. Same recipe, every time; just a different path through the graph."},{"idx":78,"label":"31","overlay":4,"forcedOverlay":true,"hidden":false,"note":"Because nixpkgs is a graph, a package is not one thing, it's a recipe you can permute.\n\n** click **\n\nHere's GNU hello, built normally.\n\n** click **\n\nThe same hello, statically linked against musl. One attribute.\n\n** click **\n\nCross-compiled for RISC-V. It won't run on my x86 laptop, which is the point.\n\n** click **\n\nOr for Windows, and we can run it under wine. Same recipe, every time; just a different path through the graph."},{"idx":79,"label":"32","overlay":0,"forcedOverlay":false,"hidden":false,"note":"It's a store. This is actually a very important distinction that separates Nix from traditional software installations: it forgoes the Filesystem Hierarchy Standard, the well-known directories like /lib and /etc that we all know and love.\n\nBy forgoing that limitation, Nix is capable of having limitless variants of a single package, since they are no longer confined to a single key space.\n\nFurthermore, dependencies of Nix software only exist within other store entries, forming a DAG."},{"idx":80,"label":"33","overlay":0,"forcedOverlay":false,"hidden":false,"note":"It's an operating system. Once you have solved producing software packages, a Linux distribution is merely a collection of software packages and a kernel."},{"idx":81,"label":"34","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Fundamentally though, Nix is the idea of modeling all software as a directed acyclic graph with an immense level of fidelity.\n\nIt's an idea that says: what if every part of our build system was accounted for?\n\nThe language, the store, the package set, the OS, the dev shells -- they're all just ways of building, storing and walking that graph."},{"idx":82,"label":"35","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Which is why the naming is so confusing. Nix the language, Nix the package manager, and NixOS the operating system are all called Nix, but none of them is the other. What they share is the graph."},{"idx":83,"label":"36","overlay":0,"forcedOverlay":false,"hidden":false,"note":"For the last part, let's go one level down and look at the mechanism.\n\nI'm going to go over very briefly how software is laid out traditionally, hopefully illuminate how it's utter madness, and then tie the thread to see how Nix solves it.\n\nA recurring theme: Docker, specifically containers, are not a solution to any of this. Containers are just a snapshot at a particular state."},{"idx":84,"label":"37","overlay":0,"forcedOverlay":false,"hidden":false,"note":"I'm going to pick Ruby, as it's an innocuous piece of software. It's written in C, present on every distribution, and would seemingly have a very small set of dependencies.\n\nHere are the Rubies on a typical machine.\n\n** click **\n\nWhich one is this? What was it built with?"},{"idx":85,"label":"37","overlay":1,"forcedOverlay":true,"hidden":false,"note":"I'm going to pick Ruby, as it's an innocuous piece of software. It's written in C, present on every distribution, and would seemingly have a very small set of dependencies.\n\nHere are the Rubies on a typical machine.\n\n** click **\n\nWhich one is this? What was it built with?"},{"idx":86,"label":"38","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Ruby's own build instructions. A C compiler, OpenSSL, libyaml, zlib -- and if you build from git, autoconf, gperf, and a Ruby to build Ruby. Plus optional extras.\n\nWhere does each of these come from on your machine? What version?"},{"idx":87,"label":"39","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Here is what the installed ruby resolves at runtime. Everything comes from one shared /lib, by name only. Whatever libz.so.1 happens to be there, wins."},{"idx":88,"label":"40","overlay":0,"forcedOverlay":false,"hidden":false,"note":"And with the full verbose tree, every library pulls in more libraries, all resolved the same way: by name, from a single global directory."},{"idx":89,"label":"41","overlay":0,"forcedOverlay":false,"hidden":false,"note":"And this is Ruby's full build graph in nixpkgs, every input accounted for. This is the thing Nix makes you model -- and once you have it, everything else we saw today falls out of it."},{"idx":90,"label":"42","overlay":0,"forcedOverlay":false,"hidden":false,"note":"A quick primer on what a binary is in Linux. All binaries on Linux are in the ELF format. It's an incredibly generic format.\n\nSpecifically, a dynamic binary must have an interpreter set, which is always the dynamic linker, and can list the libraries it needs. Note that NEEDED entries are just names -- not paths, and not versions."},{"idx":91,"label":"43","overlay":0,"forcedOverlay":false,"hidden":false,"note":"This slide won't do the concept justice at all, so I apologize; I could probably spend multiple hours talking about it.\n\nIn order to add reproducibility to the world of software management, a new concept was developed in the early 2000s as part of a PhD thesis. The idea was to nest all software underneath a single root, include a cryptographic hash in the name so similar packages could live side by side, and restrict all dependencies to other entries in the root, or store.\n\nDynamic linking relies on a feature to specify an RPATH on the binary, which supersedes the FHS search. Each NEEDED name now resolves against exact store paths.\n\nSimilar to RPATH, the developer environments set the PATH variable to isolate access to the current terminal."},{"idx":92,"label":"44","overlay":0,"forcedOverlay":false,"hidden":false,"note":"And that's how it feels once it clicks."},{"idx":93,"label":"45","overlay":0,"forcedOverlay":false,"hidden":false,"note":"Thank you! The slides and every example are online; questions welcome."}]}
