about summary refs log tree commit diff
path: root/nixpkgs/doc/build-helpers
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/doc/build-helpers')
-rw-r--r--nixpkgs/doc/build-helpers/images/dockertools.section.md701
-rw-r--r--nixpkgs/doc/build-helpers/special/checkpoint-build.section.md21
-rw-r--r--nixpkgs/doc/build-helpers/special/mkshell.section.md4
-rw-r--r--nixpkgs/doc/build-helpers/trivial-build-helpers.chapter.md398
4 files changed, 980 insertions, 144 deletions
diff --git a/nixpkgs/doc/build-helpers/images/dockertools.section.md b/nixpkgs/doc/build-helpers/images/dockertools.section.md
index 42d6e297f529..e732e0472926 100644
--- a/nixpkgs/doc/build-helpers/images/dockertools.section.md
+++ b/nixpkgs/doc/build-helpers/images/dockertools.section.md
@@ -1,33 +1,228 @@
 # pkgs.dockerTools {#sec-pkgs-dockerTools}
 
-`pkgs.dockerTools` is a set of functions for creating and manipulating Docker images according to the [Docker Image Specification v1.2.0](https://github.com/moby/moby/blob/master/image/spec/v1.2.md#docker-image-specification-v120). Docker itself is not used to perform any of the operations done by these functions.
+`pkgs.dockerTools` is a set of functions for creating and manipulating Docker images according to the [Docker Image Specification v1.3.0](https://github.com/moby/moby/blob/46f7ab808b9504d735d600e259ca0723f76fb164/image/spec/spec.md#image-json-field-descriptions).
+Docker itself is not used to perform any of the operations done by these functions.
 
 ## buildImage {#ssec-pkgs-dockerTools-buildImage}
 
-This function is analogous to the `docker build` command, in that it can be used to build a Docker-compatible repository tarball containing a single image with one or multiple layers. As such, the result is suitable for being loaded in Docker with `docker load`.
+This function builds a Docker-compatible repository tarball containing a single image.
+As such, the result is suitable for being loaded in Docker with `docker load` (see [](#ex-dockerTools-buildImage) for how to do this).
 
-The parameters of `buildImage` with relative example values are described below:
+This function will create a single layer for all files (and dependencies) that are specified in its argument.
+Only new dependencies that are not already in the existing layers will be copied.
+If you prefer to create multiple layers for the files and dependencies you want to add to the image, see [](#ssec-pkgs-dockerTools-buildLayeredImage) or [](#ssec-pkgs-dockerTools-streamLayeredImage) instead.
 
-[]{#ex-dockerTools-buildImage}
-[]{#ex-dockerTools-buildImage-runAsRoot}
+This function allows a script to be run during the layer generation process, allowing custom behaviour to affect the final results of the image (see the documentation of the `runAsRoot` and `extraCommands` attributes).
+
+The resulting repository tarball will list a single image as specified by the `name` and `tag` attributes.
+By default, that image will use a static creation date (see documentation for the `created` attribute).
+This allows `buildImage` to produce reproducible images.
+
+:::{.tip}
+When running an image built with `buildImage`, you might encounter certain errors depending on what you included in the image, especially if you did not start with any base image.
+
+If you encounter errors similar to `getProtocolByName: does not exist (no such protocol name: tcp)`, you may need to add the contents of `pkgs.iana-etc` in the `copyToRoot` attribute.
+Similarly, if you encounter errors similar to `Error_Protocol ("certificate has unknown CA",True,UnknownCa)`, you may need to add the contents of `pkgs.cacert` in the `copyToRoot` attribute.
+:::
+
+### Inputs {#ssec-pkgs-dockerTools-buildImage-inputs}
+
+`buildImage` expects an argument with the following attributes:
+
+`name` (String)
+
+: The name of the generated image.
+
+`tag` (String or Null; _optional_)
+
+: Tag of the generated image.
+  If `null`, the hash of the nix derivation will be used as the tag.
+
+  _Default value:_ `null`.
+
+`fromImage` (Path or Null; _optional_)
+
+: The repository tarball of an image to be used as the base for the generated image.
+  It must be a valid Docker image, such as one exported by `docker save`, or another image built with the `dockerTools` utility functions.
+  This can be seen as an equivalent of `FROM fromImage` in a `Dockerfile`.
+  A value of `null` can be seen as an equivalent of `FROM scratch`.
+
+  If specified, the layer created by `buildImage` will be appended to the layers defined in the base image, resulting in an image with at least two layers (one or more layers from the base image, and the layer created by `buildImage`).
+  Otherwise, the resulting image with contain the single layer created by `buildImage`.
+
+  _Default value:_ `null`.
+
+`fromImageName` (String or Null; _optional_)
+
+: Used to specify the image within the repository tarball in case it contains multiple images.
+  A value of `null` means that `buildImage` will use the first image available in the repository.
+
+  :::{.note}
+  This must be used with `fromImageTag`. Using only `fromImageName` without `fromImageTag` will make `buildImage` use the first image available in the repository.
+  :::
+
+  _Default value:_ `null`.
+
+`fromImageTag` (String or Null; _optional_)
+
+: Used to specify the image within the repository tarball in case it contains multiple images.
+  A value of `null` means that `buildImage` will use the first image available in the repository.
+
+  :::{.note}
+  This must be used with `fromImageName`. Using only `fromImageTag` without `fromImageName` will make `buildImage` use the first image available in the repository
+  :::
+
+  _Default value:_ `null`.
+
+`copyToRoot` (Path, List of Paths, or Null; _optional_)
+
+: Files to add to the generated image.
+  Anything that coerces to a path (e.g. a derivation) can also be used.
+  This can be seen as an equivalent of `ADD contents/ /` in a `Dockerfile`.
+
+  _Default value:_ `null`.
+
+`keepContentsDirlinks` (Boolean; _optional_)
+
+: When adding files to the generated image (as specified by `copyToRoot`), this attribute controls whether to preserve symlinks to directories.
+  If `false`, the symlinks will be transformed into directories.
+  This behaves the same as `rsync -k` when `keepContentsDirlinks` is `false`, and the same as `rsync -K` when `keepContentsDirlinks` is `true`.
+
+  _Default value:_ `false`.
+
+`runAsRoot` (String or Null; _optional_)
+
+: A bash script that will run as root inside a VM that contains the existing layers of the base image and the new generated layer (including the files from `copyToRoot`).
+  The script will be run with a working directory of `/`.
+  This can be seen as an equivalent of `RUN ...` in a `Dockerfile`.
+  A value of `null` means that this step in the image generation process will be skipped.
+
+  See [](#ex-dockerTools-buildImage-runAsRoot) for how to work with this attribute.
+
+  :::{.caution}
+  Using this attribute requires the `kvm` device to be available, see [`system-features`](https://nixos.org/manual/nix/stable/command-ref/conf-file.html#conf-system-features).
+  If the `kvm` device isn't available, you should consider using [`buildLayeredImage`](#ssec-pkgs-dockerTools-buildLayeredImage) or [`streamLayeredImage`](#ssec-pkgs-dockerTools-streamLayeredImage) instead.
+  Those functions allow scripts to be run as root without access to the `kvm` device.
+  :::
+
+  :::{.note}
+  At the time the script in `runAsRoot` is run, the files specified directly in `copyToRoot` will be present in the VM, but their dependencies might not be there yet.
+  Copying their dependencies into the generated image is a step that happens after `runAsRoot` finishes running.
+  :::
+
+  _Default value:_ `null`.
+
+`extraCommands` (String; _optional_)
+
+: A bash script that will run before the layer created by `buildImage` is finalised.
+  The script will be run on some (opaque) working directory which will become `/` once the layer is created.
+  This is similar to `runAsRoot`, but the script specified in `extraCommands` is **not** run as root, and does not involve creating a VM.
+  It is simply run as part of building the derivation that outputs the layer created by `buildImage`.
+
+  See [](#ex-dockerTools-buildImage-extraCommands) for how to work with this attribute, and subtle differences compared to `runAsRoot`.
+
+  _Default value:_ `""`.
+
+`config` (Attribute Set; _optional_)
+
+: Used to specify the configuration of the containers that will be started off the generated image.
+  Must be an attribute set, with each attribute as listed in the [Docker Image Specification v1.3.0](https://github.com/moby/moby/blob/46f7ab808b9504d735d600e259ca0723f76fb164/image/spec/spec.md#image-json-field-descriptions).
+
+  _Default value:_ `null`.
+
+`architecture` (String; _optional_)
+
+: Used to specify the image architecture.
+  This is useful for multi-architecture builds that don't need cross compiling.
+  If specified, its value should follow the [OCI Image Configuration Specification](https://github.com/opencontainers/image-spec/blob/main/config.md#properties), which should still be compatible with Docker.
+  According to the linked specification, all possible values for `$GOARCH` in [the Go docs](https://go.dev/doc/install/source#environment) should be valid, but will commonly be one of `386`, `amd64`, `arm`, or `arm64`.
+
+  _Default value:_ the same value from `pkgs.go.GOARCH`.
+
+`diskSize` (Number; _optional_)
+
+: Controls the disk size (in megabytes) of the VM used to run the script specified in `runAsRoot`.
+  This attribute is ignored if `runAsRoot` is `null`.
+
+  _Default value:_ 1024.
+
+`buildVMMemorySize` (Number; _optional_)
+
+: Controls the amount of memory (in megabytes) provisioned for the VM used to run the script specified in `runAsRoot`.
+  This attribute is ignored if `runAsRoot` is `null`.
+
+  _Default value:_ 512.
+
+`created` (String; _optional_)
+
+: Specifies the time of creation of the generated image.
+  This should be either a date and time formatted according to [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) or `"now"`, in which case `buildImage` will use the current date.
+
+  See [](#ex-dockerTools-buildImage-creatednow) for how to use `"now"`.
+
+  :::{.caution}
+  Using `"now"` means that the generated image will not be reproducible anymore (because the date will always change whenever it's built).
+  :::
+
+  _Default value:_ `"1970-01-01T00:00:01Z"`.
+
+`uid` (Number; _optional_)
+
+: The uid of the user that will own the files packed in the new layer built by `buildImage`.
+
+  _Default value:_ 0.
+
+`gid` (Number; _optional_)
+
+: The gid of the group that will own the files packed in the new layer built by `buildImage`.
+
+  _Default value:_ 0.
+
+`contents` **DEPRECATED**
+
+: This attribute is deprecated, and users are encouraged to use `copyToRoot` instead.
+
+### Passthru outputs {#ssec-pkgs-dockerTools-buildImage-passthru-outputs}
+
+`buildImage` defines a few [`passthru`](#var-stdenv-passthru) attributes:
+
+`buildArgs` (Attribute Set)
+
+: The argument passed to `buildImage` itself.
+  This allows you to inspect all attributes specified in the argument, as described above.
+
+`layer` (Attribute Set)
+
+: The derivation with the layer created by `buildImage`.
+  This allows easier inspection of the contents added by `buildImage` in the generated image.
+
+`imageTag` (String)
+
+: The tag of the generated image.
+  This is useful if no tag was specified in the attributes of the argument to `buildImage`, because an automatic tag will be used instead.
+  `imageTag` allows you to retrieve the value of the tag used in this case.
+
+### Examples {#ssec-pkgs-dockerTools-buildImage-examples}
+
+:::{.example #ex-dockerTools-buildImage}
+# Building a Docker image
+
+The following package builds a Docker image that runs the `redis-server` executable from the `redis` package.
+The Docker image will have name `redis` and tag `latest`.
 
 ```nix
-buildImage {
+{ dockerTools, buildEnv, redis }:
+dockerTools.buildImage {
   name = "redis";
   tag = "latest";
 
-  fromImage = someBaseImage;
-  fromImageName = null;
-  fromImageTag = "latest";
-
-  copyToRoot = pkgs.buildEnv {
+  copyToRoot = buildEnv {
     name = "image-root";
-    paths = [ pkgs.redis ];
+    paths = [ redis ];
     pathsToLink = [ "/bin" ];
   };
 
   runAsRoot = ''
-    #!${pkgs.runtimeShell}
     mkdir -p /data
   '';
 
@@ -36,68 +231,111 @@ buildImage {
     WorkingDir = "/data";
     Volumes = { "/data" = { }; };
   };
-
-  diskSize = 1024;
-  buildVMMemorySize = 512;
 }
 ```
 
-The above example will build a Docker image `redis/latest` from the given base image. Loading and running this image in Docker results in `redis-server` being started automatically.
-
-- `name` specifies the name of the resulting image. This is the only required argument for `buildImage`.
-
-- `tag` specifies the tag of the resulting image. By default it's `null`, which indicates that the nix output hash will be used as tag.
-
-- `fromImage` is the repository tarball containing the base image. It must be a valid Docker image, such as exported by `docker save`. By default it's `null`, which can be seen as equivalent to `FROM scratch` of a `Dockerfile`.
-
-- `fromImageName` can be used to further specify the base image within the repository, in case it contains multiple images. By default it's `null`, in which case `buildImage` will peek the first image available in the repository.
-
-- `fromImageTag` can be used to further specify the tag of the base image within the repository, in case an image contains multiple tags. By default it's `null`, in which case `buildImage` will peek the first tag available for the base image.
-
-- `copyToRoot` is a derivation that will be copied in the new layer of the resulting image. This can be similarly seen as `ADD contents/ /` in a `Dockerfile`. By default it's `null`.
+The result of building this package is a `.tar.gz` file that can be loaded into Docker:
+
+```shell
+$ nix-build
+(some output removed for clarity)
+building '/nix/store/yw0adm4wpsw1w6j4fb5hy25b3arr9s1v-docker-image-redis.tar.gz.drv'...
+Adding layer...
+tar: Removing leading `/' from member names
+Adding meta...
+Cooking the image...
+Finished.
+/nix/store/p4dsg62inh9d2ksy3c7bv58xa851dasr-docker-image-redis.tar.gz
+
+$ docker load -i /nix/store/p4dsg62inh9d2ksy3c7bv58xa851dasr-docker-image-redis.tar.gz
+(some output removed for clarity)
+Loaded image: redis:latest
+```
+:::
 
-- `runAsRoot` is a bash script that will run as root in an environment that overlays the existing layers of the base image with the new resulting layer, including the previously copied `contents` derivation. This can be similarly seen as `RUN ...` in a `Dockerfile`.
+:::{.example #ex-dockerTools-buildImage-runAsRoot}
+# Building a Docker image with `runAsRoot`
 
-> **_NOTE:_** Using this parameter requires the `kvm` device to be available.
+The following package builds a Docker image with the `hello` executable from the `hello` package.
+It uses `runAsRoot` to create a directory and a file inside the image.
 
-- `config` is used to specify the configuration of the containers that will be started off the built image in Docker. The available options are listed in the [Docker Image Specification v1.2.0](https://github.com/moby/moby/blob/master/image/spec/v1.2.md#image-json-field-descriptions).
+This works the same as [](#ex-dockerTools-buildImage-extraCommands), but uses `runAsRoot` instead of `extraCommands`.
 
-- `architecture` is _optional_ and used to specify the image architecture, this is useful for multi-architecture builds that don't need cross compiling. If not specified it will default to `hostPlatform`.
+```nix
+{ dockerTools, buildEnv, hello }:
+dockerTools.buildImage {
+  name = "hello";
+  tag = "latest";
 
-- `diskSize` is used to specify the disk size of the VM used to build the image in megabytes. By default it's 1024 MiB.
+  copyToRoot = buildEnv {
+    name = "image-root";
+    paths = [ hello ];
+    pathsToLink = [ "/bin" ];
+  };
 
-- `buildVMMemorySize` is used to specify the memory size of the VM to build the image in megabytes. By default it's 512 MiB.
+  runAsRoot = ''
+    mkdir -p /data
+    echo "some content" > my-file
+  '';
 
-After the new layer has been created, its closure (to which `contents`, `config` and `runAsRoot` contribute) will be copied in the layer itself. Only new dependencies that are not already in the existing layers will be copied.
+  config = {
+    Cmd = [ "/bin/hello" ];
+    WorkingDir = "/data";
+  };
+}
+```
+:::
 
-At the end of the process, only one new single layer will be produced and added to the resulting image.
+:::{.example #ex-dockerTools-buildImage-extraCommands}
+# Building a Docker image with `extraCommands`
 
-The resulting repository will only list the single image `image/tag`. In the case of [the `buildImage` example](#ex-dockerTools-buildImage), it would be `redis/latest`.
+The following package builds a Docker image with the `hello` executable from the `hello` package.
+It uses `extraCommands` to create a directory and a file inside the image.
 
-It is possible to inspect the arguments with which an image was built using its `buildArgs` attribute.
+This works the same as [](#ex-dockerTools-buildImage-runAsRoot), but uses `extraCommands` instead of `runAsRoot`.
+Note that with `extraCommands`, we can't directly reference `/` and must create files and directories as if we were already on `/`.
 
-> **_NOTE:_** If you see errors similar to `getProtocolByName: does not exist (no such protocol name: tcp)` you may need to add `pkgs.iana-etc` to `contents`.
+```nix
+{ dockerTools, buildEnv, hello }:
+dockerTools.buildImage {
+  name = "hello";
+  tag = "latest";
 
-> **_NOTE:_** If you see errors similar to `Error_Protocol ("certificate has unknown CA",True,UnknownCa)` you may need to add `pkgs.cacert` to `contents`.
+  copyToRoot = buildEnv {
+    name = "image-root";
+    paths = [ hello ];
+    pathsToLink = [ "/bin" ];
+  };
 
-By default `buildImage` will use a static date of one second past the UNIX Epoch. This allows `buildImage` to produce binary reproducible images. When listing images with `docker images`, the newly created images will be listed like this:
+  extraCommands = ''
+    mkdir -p data
+    echo "some content" > my-file
+  '';
 
-```ShellSession
-$ docker images
-REPOSITORY   TAG      IMAGE ID       CREATED        SIZE
-hello        latest   08c791c7846e   48 years ago   25.2MB
+  config = {
+    Cmd = [ "/bin/hello" ];
+    WorkingDir = "/data";
+  };
+}
 ```
+:::
+
+:::{.example #ex-dockerTools-buildImage-creatednow}
+# Building a Docker image with a creation date set to the current time
 
-You can break binary reproducibility but have a sorted, meaningful `CREATED` column by setting `created` to `now`.
+Note that using a value of `"now"` in the `created` attribute will break reproducibility.
 
 ```nix
-pkgs.dockerTools.buildImage {
+{ dockerTools, buildEnv, hello }:
+dockerTools.buildImage {
   name = "hello";
   tag = "latest";
+
   created = "now";
-  copyToRoot = pkgs.buildEnv {
+
+  copyToRoot = buildEnv {
     name = "image-root";
-    paths = [ pkgs.hello ];
+    paths = [ hello ];
     pathsToLink = [ "/bin" ];
   };
 
@@ -105,139 +343,376 @@ pkgs.dockerTools.buildImage {
 }
 ```
 
-Now the Docker CLI will display a reasonable date and sort the images as expected:
+After importing the generated repository tarball with Docker, its CLI will display a reasonable date and sort the images as expected:
 
 ```ShellSession
 $ docker images
 REPOSITORY   TAG      IMAGE ID       CREATED              SIZE
 hello        latest   de2bf4786de6   About a minute ago   25.2MB
 ```
-
-However, the produced images will not be binary reproducible.
+:::
 
 ## buildLayeredImage {#ssec-pkgs-dockerTools-buildLayeredImage}
 
-Create a Docker image with many of the store paths being on their own layer to improve sharing between images. The image is realized into the Nix store as a gzipped tarball. Depending on the intended usage, many users might prefer to use `streamLayeredImage` instead, which this function uses internally.
+`buildLayeredImage` uses [`streamLayeredImage`](#ssec-pkgs-dockerTools-streamLayeredImage) underneath to build a compressed Docker-compatible repository tarball.
+Basically, `buildLayeredImage` runs the script created by `streamLayeredImage` to save the compressed image in the Nix store.
+`buildLayeredImage` supports the same options as `streamLayeredImage`, see [`streamLayeredImage`](#ssec-pkgs-dockerTools-streamLayeredImage) for details.
 
-`name`
+:::{.note}
+Despite the similar name, [`buildImage`](#ssec-pkgs-dockerTools-buildImage) works completely differently from `buildLayeredImage` and `streamLayeredImage`.
 
-: The name of the resulting image.
+Even though some of the arguments may seem related, they cannot be interchanged.
+:::
 
-`tag` _optional_
+You can use this function to load an image in Docker with `docker load`.
+See [](#ex-dockerTools-buildLayeredImage-hello) to see how to do that.
+
+### Examples {#ssec-pkgs-dockerTools-buildLayeredImage-examples}
+
+:::{.example #ex-dockerTools-buildLayeredImage-hello}
+# Building a layered Docker image
+
+The following package builds a layered Docker image that runs the `hello` executable from the `hello` package.
+The Docker image will have name `hello` and tag `latest`.
+
+```nix
+{ dockerTools, hello }:
+dockerTools.buildLayeredImage {
+  name = "hello";
+  tag = "latest";
+
+  contents = [ hello ];
+
+  config.Cmd = [ "/bin/hello" ];
+}
+```
+
+The result of building this package is a `.tar.gz` file that can be loaded into Docker:
+
+```shell
+$ nix-build
+(some output removed for clarity)
+building '/nix/store/bk8bnrbw10nq7p8pvcmdr0qf57y6scha-hello.tar.gz.drv'...
+No 'fromImage' provided
+Creating layer 1 from paths: ['/nix/store/i93s7xxblavsacpy82zdbn4kplsyq48l-libunistring-1.1']
+Creating layer 2 from paths: ['/nix/store/ji01n9vinnj22nbrb86nx8a1ssgpilx8-libidn2-2.3.4']
+Creating layer 3 from paths: ['/nix/store/ldrslljw4rg026nw06gyrdwl78k77vyq-xgcc-12.3.0-libgcc']
+Creating layer 4 from paths: ['/nix/store/9y8pmvk8gdwwznmkzxa6pwyah52xy3nk-glibc-2.38-27']
+Creating layer 5 from paths: ['/nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1']
+Creating layer 6 with customisation...
+Adding manifests...
+Done.
+/nix/store/hxcz7snvw7f8rzhbh6mv8jq39d992905-hello.tar.gz
+
+$ docker load -i /nix/store/hxcz7snvw7f8rzhbh6mv8jq39d992905-hello.tar.gz
+(some output removed for clarity)
+Loaded image: hello:latest
+```
+:::
+
+## streamLayeredImage {#ssec-pkgs-dockerTools-streamLayeredImage}
+
+`streamLayeredImage` builds a **script** which, when run, will stream to stdout a Docker-compatible repository tarball containing a single image, using multiple layers to improve sharing between images.
+This means that `streamLayeredImage` does not output an image into the Nix store, but only a script that builds the image, saving on IO and disk/cache space, particularly with large images.
+
+You can use this function to load an image in Docker with `docker load`.
+See [](#ex-dockerTools-streamLayeredImage-hello) to see how to do that.
+
+For this function, you specify a [store path](https://nixos.org/manual/nix/stable/store/store-path) or a list of store paths to be added to the image, and the functions will automatically include any dependencies of those paths in the image.
+The function will attempt to create one layer per object in the Nix store that needs to be added to the image.
+In case there are more objects to include than available layers, the function will put the most ["popular"](https://github.com/NixOS/nixpkgs/tree/release-23.11/pkgs/build-support/references-by-popularity) objects in their own layers, and group all remaining objects into a single layer.
+
+An additional layer will be created with symlinks to the store paths you specified to be included in the image.
+These symlinks are built with [`symlinkJoin`](#trivial-builder-symlinkJoin), so they will be included in the root of the image.
+See [](#ex-dockerTools-streamLayeredImage-exploringlayers) to understand how these symlinks are laid out in the generated image.
+
+`streamLayeredImage` allows scripts to be run when creating the additional layer with symlinks, allowing custom behaviour to affect the final results of the image (see the documentation of the `extraCommands` and `fakeRootCommands` attributes).
+
+The resulting repository tarball will list a single image as specified by the `name` and `tag` attributes.
+By default, that image will use a static creation date (see documentation for the `created` attribute).
+This allows the function to produce reproducible images.
+
+### Inputs {#ssec-pkgs-dockerTools-streamLayeredImage-inputs}
+
+`streamLayeredImage` expects one argument with the following attributes:
+
+`name` (String)
+
+: The name of the generated image.
+
+`tag` (String; _optional_)
 
 : Tag of the generated image.
+  If `null`, the hash of the nix derivation will be used as the tag.
+
+  _Default value:_ `null`.
+
+`fromImage`(Path or Null; _optional_)
+
+: The repository tarball of an image to be used as the base for the generated image.
+  It must be a valid Docker image, such as one exported by `docker save`, or another image built with the `dockerTools` utility functions.
+  This can be seen as an equivalent of `FROM fromImage` in a `Dockerfile`.
+  A value of `null` can be seen as an equivalent of `FROM scratch`.
+
+  If specified, the created layers will be appended to the layers defined in the base image.
+
+  _Default value:_ `null`.
+
+`contents` (Path or List of Paths; _optional_) []{#dockerTools-buildLayeredImage-arg-contents}
+
+: Directories whose contents will be added to the generated image.
+  Things that coerce to paths (e.g. a derivation) can also be used.
+  This can be seen as an equivalent of `ADD contents/ /` in a `Dockerfile`.
+
+  All the contents specified by `contents` will be added as a final layer in the generated image.
+  They will be added as links to the actual files (e.g. links to the store paths).
+  The actual files will be added in previous layers.
+
+  _Default value:_ `[]`
+
+`config` (Attribute Set; _optional_) []{#dockerTools-buildLayeredImage-arg-config}
+
+: Used to specify the configuration of the containers that will be started off the generated image.
+  Must be an attribute set, with each attribute as listed in the [Docker Image Specification v1.3.0](https://github.com/moby/moby/blob/46f7ab808b9504d735d600e259ca0723f76fb164/image/spec/spec.md#image-json-field-descriptions).
 
-    *Default:* the output path's hash
+  If any packages are used directly in `config`, they will be automatically included in the generated image.
+  See [](#ex-dockerTools-streamLayeredImage-configclosure) for an example.
 
-`fromImage` _optional_
+  _Default value:_ `null`.
 
-: The repository tarball containing the base image. It must be a valid Docker image, such as one exported by `docker save`.
+`architecture` (String; _optional_)
 
-    *Default:* `null`, which can be seen as equivalent to `FROM scratch` of a `Dockerfile`.
+: Used to specify the image architecture.
+  This is useful for multi-architecture builds that don't need cross compiling.
+  If specified, its value should follow the [OCI Image Configuration Specification](https://github.com/opencontainers/image-spec/blob/main/config.md#properties), which should still be compatible with Docker.
+  According to the linked specification, all possible values for `$GOARCH` in [the Go docs](https://go.dev/doc/install/source#environment) should be valid, but will commonly be one of `386`, `amd64`, `arm`, or `arm64`.
 
-`contents` _optional_
+  _Default value:_ the same value from `pkgs.go.GOARCH`.
 
-: Top-level paths in the container. Either a single derivation, or a list of derivations.
+`created` (String; _optional_)
 
-    *Default:* `[]`
+: Specifies the time of creation of the generated image.
+  This should be either a date and time formatted according to [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) or `"now"`, in which case the current date will be used.
 
-`config` _optional_
+  :::{.caution}
+  Using `"now"` means that the generated image will not be reproducible anymore (because the date will always change whenever it's built).
+  :::
 
-`architecture` is _optional_ and used to specify the image architecture, this is useful for multi-architecture builds that don't need cross compiling. If not specified it will default to `hostPlatform`.
+  _Default value:_ `"1970-01-01T00:00:01Z"`.
 
-: Run-time configuration of the container. A full list of the options available is in the [Docker Image Specification v1.2.0](https://github.com/moby/moby/blob/master/image/spec/v1.2.md#image-json-field-descriptions).
+`maxLayers` (Number; _optional_) []{#dockerTools-buildLayeredImage-arg-maxLayers}
 
-    *Default:* `{}`
+: The maximum number of layers that will be used by the generated image.
+  If a `fromImage` was specified, the number of layers used by `fromImage` will be subtracted from `maxLayers` to ensure that the image generated will have at most `maxLayers`.
 
-`created` _optional_
+  :::{.caution}
+  Depending on the tool/runtime where the image will be used, there might be a limit to the number of layers that an image can have.
+  For Docker, see [this issue on GitHub](https://github.com/docker/docs/issues/8230).
+  :::
 
-: Date and time the layers were created. Follows the same `now` exception supported by `buildImage`.
+  _Default value:_ 100.
 
-    *Default:* `1970-01-01T00:00:01Z`
+`extraCommands` (String; _optional_)
 
-`maxLayers` _optional_
+: A bash script that will run in the context of the layer created with the contents specified by `contents`.
+  At the moment this script runs, only the contents directly specified by `contents` will be available as links.
 
-: Maximum number of layers to create.
+  _Default value:_ `""`.
 
-    *Default:* `100`
+`fakeRootCommands` (String; _optional_)
 
-    *Maximum:* `125`
+: A bash script that will run in the context of the layer created with the contents specified by `contents`.
+  During the process to generate that layer, the script in `extraCommands` will be run first, if specified.
+  After that, a {manpage}`fakeroot(1)` environment will be entered.
+  The script specified in `fakeRootCommands` runs inside the fakeroot environment, and the layer is then generated from the view of the files inside the fakeroot environment.
 
-`extraCommands` _optional_
+  This is useful to change the owners of the files in the layer (by running `chown`, for example), or performing any other privileged operations related to file manipulation (by default, all files in the layer will be owned by root, and the build environment doesn't have enough privileges to directly perform privileged operations on these files).
 
-: Shell commands to run while building the final layer, without access to most of the layer contents. Changes to this layer are "on top" of all the other layers, so can create additional directories and files.
+  For more details, see the manpage for {manpage}`fakeroot(1)`.
 
-`fakeRootCommands` _optional_
+  :::{.caution}
+  Due to how fakeroot works, static binaries cannot perform privileged file operations in `fakeRootCommands`, unless `enableFakechroot` is set to `true`.
+  :::
 
-: Shell commands to run while creating the archive for the final layer in a fakeroot environment. Unlike `extraCommands`, you can run `chown` to change the owners of the files in the archive, changing fakeroot's state instead of the real filesystem. The latter would require privileges that the build user does not have. Static binaries do not interact with the fakeroot environment. By default all files in the archive will be owned by root.
+  _Default value:_ `""`.
 
-`enableFakechroot` _optional_
+`enableFakechroot` (Boolean; _optional_)
 
-: Whether to run in `fakeRootCommands` in `fakechroot`, making programs behave as though `/` is the root of the image being created, while files in the Nix store are available as usual. This allows scripts that perform installation in `/` to work as expected. Considering that `fakechroot` is implemented via the same mechanism as `fakeroot`, the same caveats apply.
+: By default, the script specified in `fakeRootCommands` only runs inside a fakeroot environment.
+  If `enableFakechroot` is `true`, a more complete chroot environment will be created using [`proot`](https://proot-me.github.io/) before running the script in `fakeRootCommands`.
+  Files in the Nix store will be available.
+  This allows scripts that perform installation in `/` to work as expected.
+  This can be seen as an equivalent of `RUN ...` in a `Dockerfile`.
 
-    *Default:* `false`
+  _Default value:_ `false`
 
-### Behavior of `contents` in the final image {#dockerTools-buildLayeredImage-arg-contents}
+`includeStorePaths` (Boolean; _optional_)
 
-Each path directly listed in `contents` will have a symlink in the root of the image.
+: The files specified in `contents` are put into layers in the generated image.
+  If `includeStorePaths` is `false`, the actual files will not be included in the generated image, and only links to them will be added instead.
+  It is **not recommended** to set this to `false` unless you have other tooling to insert the store paths via other means (such as bind mounting the host store) when running containers with the generated image.
+  If you don't provide any extra tooling, the generated image won't run properly.
 
-For example:
+  See [](#ex-dockerTools-streamLayeredImage-exploringlayers) to understand the impact of setting `includeStorePaths` to `false`.
+
+  _Default value:_ `true`
+
+`passthru` (Attribute Set; _optional_)
+
+: Use this to pass any attributes as [passthru](#var-stdenv-passthru) for the resulting derivation.
+
+  _Default value:_ `{}`
+
+### Passthru outputs {#ssec-pkgs-dockerTools-streamLayeredImage-passthru-outputs}
+
+`streamLayeredImage` also defines its own [`passthru`](#var-stdenv-passthru) attributes:
+
+`imageTag` (String)
+
+: The tag of the generated image.
+  This is useful if no tag was specified in the attributes of the argument to the function, because an automatic tag will be used instead.
+  `imageTag` allows you to retrieve the value of the tag used in this case.
+
+### Examples {#ssec-pkgs-dockerTools-streamLayeredImage-examples}
+
+:::{.example #ex-dockerTools-streamLayeredImage-hello}
+# Streaming a layered Docker image
+
+The following package builds a **script** which, when run, will stream a layered Docker image that runs the `hello` executable from the `hello` package.
+The Docker image will have name `hello` and tag `latest`.
 
 ```nix
-pkgs.dockerTools.buildLayeredImage {
+{ dockerTools, hello }:
+dockerTools.streamLayeredImage {
   name = "hello";
-  contents = [ pkgs.hello ];
-}
-```
+  tag = "latest";
 
-will create symlinks for all the paths in the `hello` package:
+  contents = [ hello ];
 
-```ShellSession
-/bin/hello -> /nix/store/h1zb1padqbbb7jicsvkmrym3r6snphxg-hello-2.10/bin/hello
-/share/info/hello.info -> /nix/store/h1zb1padqbbb7jicsvkmrym3r6snphxg-hello-2.10/share/info/hello.info
-/share/locale/bg/LC_MESSAGES/hello.mo -> /nix/store/h1zb1padqbbb7jicsvkmrym3r6snphxg-hello-2.10/share/locale/bg/LC_MESSAGES/hello.mo
+  config.Cmd = [ "/bin/hello" ];
+}
 ```
 
-### Automatic inclusion of `config` references {#dockerTools-buildLayeredImage-arg-config}
+The result of building this package is a script.
+Running this script and piping it into `docker load` gives you the same image that was built in [](#ex-dockerTools-buildLayeredImage-hello).
+Note that in this case, the image is never added to the Nix store, but instead streamed directly into Docker.
+
+```shell
+$ nix-build
+(output removed for clarity)
+/nix/store/wsz2xl8ckxnlb769irvq6jv1280dfvxd-stream-hello
+
+$ /nix/store/wsz2xl8ckxnlb769irvq6jv1280dfvxd-stream-hello | docker load
+No 'fromImage' provided
+Creating layer 1 from paths: ['/nix/store/i93s7xxblavsacpy82zdbn4kplsyq48l-libunistring-1.1']
+Creating layer 2 from paths: ['/nix/store/ji01n9vinnj22nbrb86nx8a1ssgpilx8-libidn2-2.3.4']
+Creating layer 3 from paths: ['/nix/store/ldrslljw4rg026nw06gyrdwl78k77vyq-xgcc-12.3.0-libgcc']
+Creating layer 4 from paths: ['/nix/store/9y8pmvk8gdwwznmkzxa6pwyah52xy3nk-glibc-2.38-27']
+Creating layer 5 from paths: ['/nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1']
+Creating layer 6 with customisation...
+Adding manifests...
+Done.
+(some output removed for clarity)
+Loaded image: hello:latest
+```
+:::
 
-The closure of `config` is automatically included in the closure of the final image.
+:::{.example #ex-dockerTools-streamLayeredImage-exploringlayers}
+# Exploring the layers in an image built with `streamLayeredImage`
 
-This allows you to make very simple Docker images with very little code. This container will start up and run `hello`:
+Assume the following package, which builds a layered Docker image with the `hello` package.
 
 ```nix
-pkgs.dockerTools.buildLayeredImage {
+{ dockerTools, hello }:
+dockerTools.streamLayeredImage {
   name = "hello";
-  config.Cmd = [ "${pkgs.hello}/bin/hello" ];
+  contents = [ hello ];
 }
 ```
 
-### Adjusting `maxLayers` {#dockerTools-buildLayeredImage-arg-maxLayers}
+The `hello` package depends on 4 other packages:
 
-Increasing the `maxLayers` increases the number of layers which have a chance to be shared between different images.
+```shell
+$ nix-store --query -R $(nix-build -A hello)
+/nix/store/i93s7xxblavsacpy82zdbn4kplsyq48l-libunistring-1.1
+/nix/store/ji01n9vinnj22nbrb86nx8a1ssgpilx8-libidn2-2.3.4
+/nix/store/ldrslljw4rg026nw06gyrdwl78k77vyq-xgcc-12.3.0-libgcc
+/nix/store/9y8pmvk8gdwwznmkzxa6pwyah52xy3nk-glibc-2.38-27
+/nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1
+```
 
-Modern Docker installations support up to 128 layers, but older versions support as few as 42.
+This means that all these packages will be included in the image generated by `streamLayeredImage`.
+It will put each package in its own layer, for a total of 5 layers with actual files in them.
+A final layer will be created only with symlinks for the `hello` package.
 
-If the produced image will not be extended by other Docker builds, it is safe to set `maxLayers` to `128`. However, it will be impossible to extend the image further.
+The image generated will have the following directory structure (some directories were collapsed for readability):
 
-The first (`maxLayers-2`) most "popular" paths will have their own individual layers, then layer \#`maxLayers-1` will contain all the remaining "unpopular" paths, and finally layer \#`maxLayers` will contain the Image configuration.
+```
+├── bin
+│   └── hello → /nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1/bin/hello
+├── nix
+│   └── store
+│       ├─⊕ 9y8pmvk8gdwwznmkzxa6pwyah52xy3nk-glibc-2.38-27
+│       ├─⊕ i93s7xxblavsacpy82zdbn4kplsyq48l-libunistring-1.1
+│       ├─⊕ ji01n9vinnj22nbrb86nx8a1ssgpilx8-libidn2-2.3.4
+│       ├─⊕ ldrslljw4rg026nw06gyrdwl78k77vyq-xgcc-12.3.0-libgcc
+│       └─⊕ zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1
+└── share
+    ├── info
+    │   └── hello.info → /nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1/share/info/hello.info
+    ├─⊕ locale
+    └── man
+        └── man1
+            └── hello.1.gz → /nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1/share/man/man1/hello.1.gz
+```
 
-Docker's Layers are not inherently ordered, they are content-addressable and are not explicitly layered until they are composed in to an Image.
+Each of the packages in `/nix/store` comes from a layer in the image.
+The final layer adds the `/bin` and `/share` directories, but they only contain links to the actual files in `/nix/store`.
 
-## streamLayeredImage {#ssec-pkgs-dockerTools-streamLayeredImage}
+If our package sets `includeStorePaths` to `false`, we'll end up with only the final layer with the links, but the actual files won't exist in the image:
 
-Builds a script which, when run, will stream an uncompressed tarball of a Docker image to stdout. The arguments to this function are as for `buildLayeredImage`. This method of constructing an image does not realize the image into the Nix store, so it saves on IO and disk/cache space, particularly with large images.
+```nix
+{ dockerTools, hello }:
+dockerTools.streamLayeredImage {
+  name = "hello";
+  contents = [ hello ];
+}
+```
 
-The image produced by running the output script can be piped directly into `docker load`, to load it into the local docker daemon:
+After building this package, the image will have the following directory structure:
 
-```ShellSession
-$(nix-build) | docker load
+```
+├── bin
+│   └── hello → /nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1/bin/hello
+└── share
+    ├── info
+    │   └── hello.info → /nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1/share/info/hello.info
+    ├─⊕ locale
+    └── man
+        └── man1
+            └── hello.1.gz → /nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1/share/man/man1/hello.1.gz
 ```
 
-Alternatively, the image be piped via `gzip` into `skopeo`, e.g., to copy it into a registry:
+Note how the links point to paths in `/nix/store`, but they're not included in the image itself.
+This is why you need extra tooling when using `includeStorePaths`:
+a container created from such image won't find any of the files it needs to run otherwise.
+:::
 
-```ShellSession
-$(nix-build) | gzip --fast | skopeo copy docker-archive:/dev/stdin docker://some_docker_registry/myimage:tag
+::: {.example #ex-dockerTools-streamLayeredImage-configclosure}
+# Building a layered Docker image with packages directly in `config`
+
+The closure of `config` is automatically included in the generated image.
+The following package shows a more compact way to create the same output generated in [](#ex-dockerTools-streamLayeredImage-hello).
+
+```nix
+{ dockerTools, hello, lib }:
+dockerTools.streamLayeredImage {
+  name = "hello";
+  tag = "latest";
+  config.Cmd = [ "${lib.getExe hello}" ];
+}
 ```
+:::
 
 ## pullImage {#ssec-pkgs-dockerTools-fetchFromRegistry}
 
diff --git a/nixpkgs/doc/build-helpers/special/checkpoint-build.section.md b/nixpkgs/doc/build-helpers/special/checkpoint-build.section.md
index 5f01e699b947..f60afe801ed4 100644
--- a/nixpkgs/doc/build-helpers/special/checkpoint-build.section.md
+++ b/nixpkgs/doc/build-helpers/special/checkpoint-build.section.md
@@ -2,35 +2,38 @@
 
 `pkgs.checkpointBuildTools` provides a way to build derivations incrementally. It consists of two functions to make checkpoint builds using Nix possible.
 
-For hermeticity, Nix derivations do not allow any state to carry over between builds, making a transparent incremental build within a derivation impossible.
+For hermeticity, Nix derivations do not allow any state to be carried over between builds, making a transparent incremental build within a derivation impossible.
 
 However, we can tell Nix explicitly what the previous build state was, by representing that previous state as a derivation output. This allows the passed build state to be used for an incremental build.
 
 To change a normal derivation to a checkpoint based build, these steps must be taken:
-  - apply `prepareCheckpointBuild` on the desired derivation
-    e.g.:
+  - apply `prepareCheckpointBuild` on the desired derivation, e.g.
 ```nix
 checkpointArtifacts = (pkgs.checkpointBuildTools.prepareCheckpointBuild pkgs.virtualbox);
 ```
-  - change something you want in the sources of the package. (e.g. using a source override)
+  - change something you want in the sources of the package, e.g. use a source override:
 ```nix
 changedVBox = pkgs.virtualbox.overrideAttrs (old: {
   src = path/to/vbox/sources;
-}
+});
 ```
-  - use `mkCheckpointedBuild changedVBox buildOutput`
+  - use `mkCheckpointBuild changedVBox checkpointArtifacts`
   - enjoy shorter build times
 
 ## Example {#sec-checkpoint-build-example}
 ```nix
-{ pkgs ? import <nixpkgs> {} }: with (pkgs) checkpointBuildTools;
+{ pkgs ? import <nixpkgs> {} }:
 let
-  helloCheckpoint = checkpointBuildTools.prepareCheckpointBuild pkgs.hello;
+  inherit (pkgs.checkpointBuildTools)
+    prepareCheckpointBuild
+    mkCheckpointBuild
+    ;
+  helloCheckpoint = prepareCheckpointBuild pkgs.hello;
   changedHello = pkgs.hello.overrideAttrs (_: {
     doCheck = false;
     patchPhase = ''
       sed -i 's/Hello, world!/Hello, Nix!/g' src/hello.c
     '';
   });
-in checkpointBuildTools.mkCheckpointBuild changedHello helloCheckpoint
+in mkCheckpointBuild changedHello helloCheckpoint
 ```
diff --git a/nixpkgs/doc/build-helpers/special/mkshell.section.md b/nixpkgs/doc/build-helpers/special/mkshell.section.md
index 96d43535955f..e39bef7468e3 100644
--- a/nixpkgs/doc/build-helpers/special/mkshell.section.md
+++ b/nixpkgs/doc/build-helpers/special/mkshell.section.md
@@ -29,6 +29,10 @@ pkgs.mkShell {
 
 ... all the attributes of `stdenv.mkDerivation`.
 
+## Variants {#sec-pkgs-mkShell-variants}
+
+`pkgs.mkShellNoCC` is a variant that uses `stdenvNoCC` instead of `stdenv` as base environment. This is useful if no C compiler is needed in the shell environment.
+
 ## Building the shell {#sec-pkgs-mkShell-building}
 
 This derivation output will contain a text file that contains a reference to
diff --git a/nixpkgs/doc/build-helpers/trivial-build-helpers.chapter.md b/nixpkgs/doc/build-helpers/trivial-build-helpers.chapter.md
index a0cda86a6607..4648c7985542 100644
--- a/nixpkgs/doc/build-helpers/trivial-build-helpers.chapter.md
+++ b/nixpkgs/doc/build-helpers/trivial-build-helpers.chapter.md
@@ -1,6 +1,7 @@
 # Trivial build helpers {#chap-trivial-builders}
 
-Nixpkgs provides a couple of functions that help with building derivations. The most important one, `stdenv.mkDerivation`, has already been documented above. The following functions wrap `stdenv.mkDerivation`, making it easier to use in certain cases.
+Nixpkgs provides a variety of wrapper functions that help build commonly useful derivations.
+Like [`stdenv.mkDerivation`](#sec-using-stdenv), each of these build helpers creates a derivation, but the arguments passed are different (usually simpler) from those required by `stdenv.mkDerivation`.
 
 ## `runCommand` {#trivial-builder-runCommand}
 
@@ -58,63 +59,416 @@ Variant of `runCommand` that forces the derivation to be built locally, it is no
 This sets [`allowSubstitutes` to `false`](https://nixos.org/nix/manual/#adv-attr-allowSubstitutes), so only use `runCommandLocal` if you are certain the user will always have a builder for the `system` of the derivation. This should be true for most trivial use cases (e.g., just copying some files to a different location or adding symlinks) because there the `system` is usually the same as `builtins.currentSystem`.
 :::
 
-## `writeTextFile`, `writeText`, `writeTextDir`, `writeScript`, `writeScriptBin` {#trivial-builder-writeText}
+## Writing text files {#trivial-builder-text-writing}
 
-These functions write `text` to the Nix store. This is useful for creating scripts from Nix expressions. `writeTextFile` takes an attribute set and expects two arguments, `name` and `text`. `name` corresponds to the name used in the Nix store path. `text` will be the contents of the file. You can also set `executable` to true to make this file have the executable bit set.
+Nixpkgs provides the following functions for producing derivations which write text files or executable scripts into the Nix store.
+They are useful for creating files from Nix expression, and are all implemented as convenience wrappers around `writeTextFile`.
 
-Many more commands wrap `writeTextFile` including `writeText`, `writeTextDir`, `writeScript`, and `writeScriptBin`. These are convenience functions over `writeTextFile`.
+Each of these functions will cause a derivation to be produced.
+When you coerce the result of each of these functions to a string with [string interpolation](https://nixos.org/manual/nix/stable/language/string-interpolation) or [`builtins.toString`](https://nixos.org/manual/nix/stable/language/builtins#builtins-toString), it will evaluate to the [store path](https://nixos.org/manual/nix/stable/store/store-path) of this derivation.
+
+:::: {.note}
+Some of these functions will put the resulting files within a directory inside the [derivation output](https://nixos.org/manual/nix/stable/language/derivations#attr-outputs).
+If you need to refer to the resulting files somewhere else in a Nix expression, append their path to the derivation's store path.
+
+For example, if the file destination is a directory:
 
-Here are a few examples:
 ```nix
-# Writes my-file to /nix/store/<store path>
-writeTextFile {
+my-file = writeTextFile {
   name = "my-file";
   text = ''
     Contents of File
   '';
+  destination = "/share/my-file";
 }
-# See also the `writeText` helper function below.
+```
 
-# Writes executable my-file to /nix/store/<store path>/bin/my-file
+Remember to append "/share/my-file" to the resulting store path when using it elsewhere:
+
+```nix
+writeShellScript "evaluate-my-file.sh" ''
+  cat ${my-file}/share/my-file
+'';
+```
+::::
+
+### `writeTextFile` {#trivial-builder-writeTextFile}
+
+Write a text file to the Nix store.
+
+`writeTextFile` takes an attribute set with the following possible attributes:
+
+`name` (String)
+
+: Corresponds to the name used in the Nix store path identifier.
+
+`text` (String)
+
+: The contents of the file.
+
+`executable` (Bool, _optional_)
+
+: Make this file have the executable bit set.
+
+  Default: `false`
+
+`destination` (String, _optional_)
+
+: A subpath under the derivation's output path into which to put the file.
+  Subdirectories are created automatically when the derivation is realised.
+
+  By default, the store path itself will be a file containing the text contents.
+
+  Default: `""`
+
+`checkPhase` (String, _optional_)
+
+: Commands to run after generating the file.
+
+  Default: `""`
+
+`meta` (Attribute set, _optional_)
+
+: Additional metadata for the derivation.
+
+  Default: `{}`
+
+`allowSubstitutes` (Bool, _optional_)
+
+: Whether to allow substituting from a binary cache.
+  Passed through to [`allowSubsitutes`](https://nixos.org/manual/nix/stable/language/advanced-attributes#adv-attr-allowSubstitutes) of the underlying call to `builtins.derivation`.
+
+  It defaults to `false`, as running the derivation's simple `builder` executable locally is assumed to be faster than network operations.
+  Set it to true if the `checkPhase` step is expensive.
+
+  Default: `false`
+
+`preferLocalBuild` (Bool, _optional_)
+
+: Whether to prefer building locally, even if faster [remote build machines](https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-substituters) are available.
+
+  Passed through to [`preferLocalBuild`](https://nixos.org/manual/nix/stable/language/advanced-attributes#adv-attr-preferLocalBuild) of the underlying call to `builtins.derivation`.
+
+  It defaults to `true` for the same reason `allowSubstitutes` defaults to `false`.
+
+  Default: `true`
+
+The resulting store path will include some variation of the name, and it will be a file unless `destination` is used, in which case it will be a directory.
+
+::: {.example #ex-writeTextFile}
+# Usage 1 of `writeTextFile`
+
+Write `my-file` to `/nix/store/<store path>/some/subpath/my-cool-script`, making it executable.
+Also run a check on the resulting file in a `checkPhase`, and supply values for the less-used options.
+
+```nix
+writeTextFile {
+  name = "my-cool-script";
+  text = ''
+    #!/bin/sh
+    echo "This is my cool script!"
+  '';
+  executable = true;
+  destination = "/some/subpath/my-cool-script";
+  checkPhase = ''
+    ${pkgs.shellcheck}/bin/shellcheck $out/some/subpath/my-cool-script
+  '';
+  meta = {
+    license = pkgs.lib.licenses.cc0;
+  };
+  allowSubstitutes = true;
+  preferLocalBuild = false;
+};
+```
+:::
+
+::: {.example #ex2-writeTextFile}
+# Usage 2 of `writeTextFile`
+
+Write the string `Contents of File` to `/nix/store/<store path>`.
+See also the [](#trivial-builder-writeText) helper function.
+
+```nix
 writeTextFile {
   name = "my-file";
   text = ''
     Contents of File
   '';
+}
+```
+:::
+
+::: {.example #ex3-writeTextFile}
+# Usage 3 of `writeTextFile`
+
+Write an executable script `my-script` to `/nix/store/<store path>/bin/my-script`.
+See also the [](#trivial-builder-writeScriptBin) helper function.
+
+```nix
+writeTextFile {
+  name = "my-script";
+  text = ''
+    echo "hi"
+  '';
   executable = true;
-  destination = "/bin/my-file";
+  destination = "/bin/my-script";
 }
-# Writes contents of file to /nix/store/<store path>
+```
+:::
+
+### `writeText` {#trivial-builder-writeText}
+
+Write a text file to the Nix store
+
+`writeText` takes the following arguments:
+a string.
+
+`name` (String)
+
+: The name used in the Nix store path.
+
+`text` (String)
+
+: The contents of the file.
+
+The store path will include the name, and it will be a file.
+
+::: {.example #ex-writeText}
+# Usage of `writeText`
+
+Write the string `Contents of File` to `/nix/store/<store path>`:
+
+```nix
 writeText "my-file"
   ''
   Contents of File
   '';
-# Writes contents of file to /nix/store/<store path>/share/my-file
+```
+:::
+
+This is equivalent to:
+
+```nix
+writeTextFile {
+  name = "my-file";
+  text = ''
+    Contents of File
+  '';
+}
+```
+
+### `writeTextDir` {#trivial-builder-writeTextDir}
+
+Write a text file within a subdirectory of the Nix store.
+
+`writeTextDir` takes the following arguments:
+
+`path` (String)
+
+: The destination within the Nix store path under which to create the file.
+
+`text` (String)
+
+: The contents of the file.
+
+The store path will be a directory.
+
+::: {.example #ex-writeTextDir}
+# Usage of `writeTextDir`
+
+Write the string `Contents of File` to `/nix/store/<store path>/share/my-file`:
+
+```nix
 writeTextDir "share/my-file"
   ''
   Contents of File
   '';
-# Writes my-file to /nix/store/<store path> and makes executable
+```
+:::
+
+This is equivalent to:
+
+```nix
+writeTextFile {
+  name = "my-file";
+  text = ''
+    Contents of File
+  '';
+  destination = "share/my-file";
+}
+```
+
+### `writeScript` {#trivial-builder-writeScript}
+
+Write an executable script file to the Nix store.
+
+`writeScript` takes the following arguments:
+
+`name` (String)
+
+: The name used in the Nix store path.
+
+`text` (String)
+
+: The contents of the file.
+
+The created file is marked as executable.
+The store path will include the name, and it will be a file.
+
+::: {.example #ex-writeScript}
+# Usage of `writeScript`
+
+Write the string `Contents of File` to `/nix/store/<store path>` and make the file executable.
+
+```nix
 writeScript "my-file"
   ''
   Contents of File
   '';
-# Writes my-file to /nix/store/<store path>/bin/my-file and makes executable.
-writeScriptBin "my-file"
+```
+:::
+
+This is equivalent to:
+
+```nix
+writeTextFile {
+  name = "my-file";
+  text = ''
+    Contents of File
+  '';
+  executable = true;
+}
+```
+
+### `writeScriptBin` {#trivial-builder-writeScriptBin}
+
+Write a script within a `bin` subirectory of a directory in the Nix store.
+This is for consistency with the convention of software packages placing executables under `bin`.
+
+`writeScriptBin` takes the following arguments:
+
+`name` (String)
+
+: The name used in the Nix store path and within the file created under the store path.
+
+`text` (String)
+
+: The contents of the file.
+
+The created file is marked as executable.
+The file's contents will be put into `/nix/store/<store path>/bin/<name>`.
+The store path will include the the name, and it will be a directory.
+
+::: {.example #ex-writeScriptBin}
+# Usage of `writeScriptBin`
+
+```nix
+writeScriptBin "my-script"
   ''
-  Contents of File
+  echo "hi"
   '';
-# Writes my-file to /nix/store/<store path> and makes executable.
-writeShellScript "my-file"
+```
+:::
+
+This is equivalent to:
+
+```nix
+writeTextFile {
+  name = "my-script";
+  text = ''
+    echo "hi"
+  '';
+  executable = true;
+  destination = "bin/my-script"
+}
+```
+
+### `writeShellScript` {#trivial-builder-writeShellScript}
+
+Write a Bash script to the store.
+
+`writeShellScript` takes the following arguments:
+
+`name` (String)
+
+: The name used in the Nix store path.
+
+`text` (String)
+
+: The contents of the file.
+
+The created file is marked as executable.
+The store path will include the name, and it will be a file.
+
+This function is almost exactly like [](#trivial-builder-writeScript), except that it prepends to the file a [shebang](https://en.wikipedia.org/wiki/Shebang_%28Unix%29) line that points to the version of Bash used in Nixpkgs.
+<!-- this cannot be changed in practice, so there is no point pretending it's somehow generic -->
+
+::: {.example #ex-writeShellScript}
+# Usage of `writeShellScript`
+
+```nix
+writeShellScript "my-script"
   ''
-  Contents of File
+  echo "hi"
+  '';
+```
+:::
+
+This is equivalent to:
+
+```nix
+writeTextFile {
+  name = "my-script";
+  text = ''
+    #! ${pkgs.runtimeShell}
+    echo "hi"
   '';
-# Writes my-file to /nix/store/<store path>/bin/my-file and makes executable.
-writeShellScriptBin "my-file"
+  executable = true;
+}
+```
+
+### `writeShellScriptBin` {#trivial-builder-writeShellScriptBin}
+
+Write a Bash script to a "bin" subdirectory of a directory in the Nix store.
+
+`writeShellScriptBin` takes the following arguments:
+
+`name` (String)
+
+: The name used in the Nix store path and within the file generated under the store path.
+
+`text` (String)
+
+: The contents of the file.
+
+The file's contents will be put into `/nix/store/<store path>/bin/<name>`.
+The store path will include the the name, and it will be a directory.
+
+This function is a combination of [](#trivial-builder-writeShellScript) and [](#trivial-builder-writeScriptBin).
+
+::: {.example #ex-writeShellScriptBin}
+# Usage of `writeShellScriptBin`
+
+```nix
+writeShellScriptBin "my-script"
   ''
-  Contents of File
+  echo "hi"
   '';
+```
+:::
+
+This is equivalent to:
 
+```nix
+writeTextFile {
+  name = "my-script";
+  text = ''
+    #! ${pkgs.runtimeShell}
+    echo "hi"
+  '';
+  executable = true;
+  destination = "bin/my-script"
+}
 ```
 
 ## `concatTextFile`, `concatText`, `concatScript` {#trivial-builder-concatText}