{
  description = "Development environments on your infrastructure";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    drpc.url = "github:storj/drpc/v0.0.32";
  };

  outputs = { self, nixpkgs, flake-utils, drpc }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
        formatter = pkgs.nixpkgs-fmt;
        # Check in https://search.nixos.org/packages to find new packages.
        # Use `nix --extra-experimental-features nix-command --extra-experimental-features flakes flake update`
        # to update the lock file if packages are out-of-date.

        # From https://nixos.wiki/wiki/Google_Cloud_SDK
        gdk = pkgs.google-cloud-sdk.withExtraComponents ([pkgs.google-cloud-sdk.components.gke-gcloud-auth-plugin]);

        devShellPackages = with pkgs; [
          bat
          cairo
          curl
          drpc.defaultPackage.${system}
          gcc
          gdk
          getopt
          git
          gh
          gnumake
          gnused
          go_1_20
          go-migrate
          golangci-lint
          gopls
          gotestsum
          jq
          kubectl
          kubectx
          kubernetes-helm
          less
          # Needed for many LD system libs!
          libuuid
          mockgen
          nfpm
          nodejs
          nodePackages.pnpm
          nodePackages.prettier
          nodePackages.typescript
          nodePackages.typescript-language-server
          openssh
          openssl
          pango
          pixman
          pkg-config
          postgresql_13
          protobuf
          protoc-gen-go
          ripgrep
          sapling
          shellcheck
          shfmt
          sqlc
          # strace is not available on OSX
          (if system == "aarch64-darwin" then null else strace)
          terraform
          typos
          vim
          wget
          yarn
          yq-go
          zip
          zsh
          zstd
        ];
        # We separate these to reduce the size of the dev shell for packages that we only
        # want in the image.
        devImagePackages = with pkgs; [
          docker
          exa
          freetype
          glib
          harfbuzz
          nix
          nixpkgs-fmt
          screen
        ];

        # This is the base image for our Docker container used for development.
        # Use `nix-prefetch-docker ubuntu --arch amd64 --image-tag lunar` to get this.
        baseDevEnvImage = pkgs.dockerTools.pullImage {
          imageName = "ubuntu";
          imageDigest = "sha256:7a520eeb6c18bc6d32a21bb7edcf673a7830813c169645d51c949cecb62387d0";
          sha256 = "ajZzFSG/q7F5wAXfBOPpYBT+aVy8lqAXtBzkmAe2SeE=";
          finalImageName = "ubuntu";
          finalImageTag = "lunar";
        };
        # This is an intermediate stage that adds sudo with the setuid bit set.
        # Nix doesn't allow setuid binaries in the store, so we have to do this
        # in a separate stage.
        intermediateDevEnvImage = pkgs.dockerTools.buildImage {
          name = "intermediate";
          fromImage = baseDevEnvImage;
          runAsRoot = ''
            #!${pkgs.runtimeShell}
            ${pkgs.dockerTools.shadowSetup}
            userdel ubuntu
            groupadd docker
            useradd coder \
              --create-home \
              --shell=/bin/bash \
              --uid=1000 \
              --user-group \
              --groups docker
            cp ${pkgs.sudo}/bin/sudo usr/bin/sudo
            chmod 4755 usr/bin/sudo
            mkdir -p /etc/init.d
          '';
        };
        allPackages = devShellPackages ++ devImagePackages;
        # Environment variables that live in `/etc/environment` in the container.
        # These will also be applied to the container config.
        devEnvVars = [
          "PATH=${pkgs.lib.makeBinPath (allPackages)}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/coder/go/bin"
          "LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath allPackages}"
          # This setting prevents Go from using the public checksum database for
          # our module path prefixes. It is required because these are in private
          # repositories that require authentication.
          #
          # For details, see: https://golang.org/ref/mod#private-modules
          "GOPRIVATE=coder.com,cdr.dev,go.coder.com,github.com/cdr,github.com/coder"
          # Increase memory allocation to NodeJS
          "NODE_OPTIONS=--max_old_space_size=8192"
          "TERM=xterm-256color"
          "LANG=en_US.UTF-8"
          "LOCALE_ARCHIVE=/usr/lib/locale/locale-archive"
        ];
        # Builds our development environment image with all the tools included.
        # Using Nix instead of Docker is **significantly** faster. This _build_
        # doesn't really build anything, it just copies pre-built binaries into
        # a container and adds them to the $PATH.
        #
        # To test changes and iterate on this, you can run:
        # > nix build .#devEnvImage && ./result | docker load
        # This will import the image into your local Docker daemon.
        devEnvImage = pkgs.dockerTools.streamLayeredImage {
          name = "codercom/oss-dogfood";
          tag = "latest";
          fromImage = intermediateDevEnvImage;
          maxLayers = 64;
          contents = [
            # Required for `sudo` to persist the proper `PATH`.
            (
              pkgs.writeTextDir "etc/environment" (pkgs.lib.strings.concatLines devEnvVars)
            )
            # Allows `coder` to use `sudo` without a password.
            (
              pkgs.writeTextDir "etc/sudoers" ''
                coder ALL=(ALL) NOPASSWD:ALL
              ''
            )
            # Also allows `coder` to use `sudo` without a password.
            (
              pkgs.writeTextDir "etc/pam.d/other" ''
                account sufficient pam_unix.so
                auth sufficient pam_rootok.so
                password requisite pam_unix.so nullok yescrypt
                session required pam_unix.so
              ''
            )
            # This allows users to chsh.
            (
              pkgs.writeTextDir "etc/pam.d/chsh" ''
                auth        sufficient  pam_rootok.so
              ''
            )
            # The default Nix config!
            (
              pkgs.writeTextDir "etc/nix/nix.conf" ''
                experimental-features = nix-command flakes
              ''
            )
            # Allow people to change shells!
            (
              pkgs.writeTextDir "etc/shells" ''
                /bin/bash
                ${pkgs.zsh}/bin/zsh
              ''
            )
            # This is the debian script for managing Docker with `sudo service docker ...`.
            (
              pkgs.writeTextFile {
                name = "docker";
                destination = "/etc/init.d/docker";
                executable = true;
                text = (builtins.readFile (
                  pkgs.fetchFromGitHub
                    {
                      owner = "moby";
                      repo = "moby";
                      rev = "ae737656f9817fbd5afab96aa083754cfb81aab0";
                      sha256 = "sha256-oS3WplsxhKHCuHwL4/ytsCNJ1N/SZhlUZmzZTf81AoE=";
                    } + "/contrib/init/sysvinit-debian/docker"
                ));
              }
            )
            # The Docker script above looks here for the daemon binary location.
            # Because we're injecting it with Nix, it's not in the default spot.
            (
              pkgs.writeTextDir "etc/default/docker" ''
                DOCKERD=${pkgs.docker}/bin/dockerd
              ''
            )
            # The same as `sudo apt install ca-certificates -y'.
            (
              pkgs.writeTextDir "etc/ssl/certs/ca-certificates.crt"
                (builtins.readFile "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt")
            )
          ];
          # Required for the UTF-8 locale to exist!
          extraCommands = ''
            mkdir -p usr/lib/locale
            cp -a ${pkgs.glibcLocales}/lib/locale/locale-archive usr/lib/locale/locale-archive
          '';

          config = {
            Env = devEnvVars;
            Entrypoint = [ "/bin/bash" ];
            User = "coder";
          };
        };
      in
      {
        packages = {
          devEnvImage = devEnvImage;
        };
        defaultPackage = formatter; # or replace it with your desired default package.
        devShell = pkgs.mkShell { buildInputs = devShellPackages; };
      }
    );
}
