In this blog post, we will dive into the usage of Nixpacks. Nixpacks is a tool used by many Platform-as-a-Service solutions, including NX1. It is a standard way to build container images for deployment. We will see its regular use cases and customisation possibilities to fit any deployment need.

What is Nixpacks

Nixpacks is a tool that turns an application source code into a portable image that can be deployed anywhere. It is built by the teams at Railway as an alternative to buildpacks. Based on containers, it builds an OCI (Open Containers Initiative) compatible image for your application.

Nixpacks supports a wide variety of use cases. It is customizable and extendable for any specific need. Under the hood, Nixpacks relies on Nix for OS and language-level dependencies and on docker as a container engine.

Prerequisites and installation

To use Nixpacks, docker needs to be installed on your machine. Refer to the following page to install docker on your platform.

To install Nixpacks on Mac OS, in a terminal, run the following command:

brew install nixpacks

Alternatively, on all platforms run the following in a terminal:

curl -sSL https://nixpacks.com/install.sh | bash

To see other installation platforms, refer to the following page.

Using Nixpacks

In the following section, we will dive into using the nixpacks command-line tool.

To begin, download the source code of an application and open a terminal in the source code folder. For this blog post, we will use the following sample NextJS application.

nixpacks build

The main command for nixpacks, it looks into the source code of your application to infer the providers and libraries needed to set up, install, build, and run your application, then builds the application image.

To build an image, run the following command:

nixpacks build . —name example-app
  • `.` is the target directory holding the application source code (here, the current directory)
  • `example-app` is the name given to the built image

Nixpacks will then output the build plan for the application and start the build process.

Here is an example of the build process:

You can see the different steps for setup, install, build, and start phases for the application as well as the detailed build process for the image

⚠️ If you encounter an error here:

  • Make sure you are in the correct directory within your terminal.
  • Make sure the docker daemon is running on your machine.

nixpacks plan

You can use nixpacks to output the build plan using the following command:

nixpacks plan .
  • `.` is the target directory holding the application source code (here, the current directory)

This outputs the build plan used for the application in a JSON format, here is an example of the output:

You can see within the results the different steps used (setup, install, build, start) with the commands, variables and parameters used to complete the build successfully.

Customising and Extending Nixpacks

By default, Nixpacks creates setup, install, build ,and start plans according to the language and framework used. You can also decide to customise each step to fit your own workflow.

Changing build configuration using nixpacks.toml

To customise steps, you can define a nixpacks.toml file that contains specifics for your build.

To see an example of that file, start by creating it using the default plan by executing this command:

nixpacks plan . -f toml > nixpacks.toml

This uses the nixpacks plan command to generate the configuration in a TOML format, creating the nixpacks.toml file.

You can view the content of the nixpacks.toml file, , it should look as follows:

providers = []
buildImage = 'ghcr.io/railwayapp/nixpacks:ubuntu-1707782610'

[variables]
CI = 'true'
NIXPACKS_METADATA = 'node'
NODE_ENV = 'production'
NPM_CONFIG_PRODUCTION = 'false'
[phases.build]
dependsOn = ['install']
cmds = ['yarn run build']
cacheDirectories = [
    '.next/cache',
    'node_modules/.cache',
]

[phases.install]
dependsOn = ['setup']
cmds = ['yarn install --frozen-lockfile']
cacheDirectories = ['/usr/local/share/.cache/yarn/v6']
paths = ['/app/node_modules/.bin']

[phases.setup]
nixPkgs = [
    'nodejs_18',
    'yarn-1_x',
    'openssl',
]
nixOverlays = ['https://github.com/railwayapp/nix-npm-overlay/archive/main.tar.gz']
nixpkgsArchive = 'bf744fe90419885eefced41b3e5ae442d732712d'

[start]
cmd = 'yarn run start'

Here you can customise the file, for instance, let’s change the start command. Change the [start] section to:

[start]
cmd = 'echo “custom start command”; yarn run start'

Then rebuild your image with the following command:

nixpacks build . --name custom-build

You can assert that the start command is now the new one you defined within the nixpacks.toml, running the container will use this updated configuration from now on.

You can see the updated start phase in the nixpacks build output.

To read more details on how to customise your nixpacks.toml file, see the nixpacks documentation.

Creating a Dockerfile via nixpacks

For some use cases, it is preferable to output a Dockerfile that can then be customised or used separately.

To do so, use the following command while building using nixpacks:

nixpacks build . -o .

The `-o` option followed by a path (here `.` , current directory) will generate a .nixpacks folder containing the generated Dockerfile and related packages.

You can decide to use the Dockerfile any way you desire, using docker build works.

Within the linked repository, we decided to create a docker-compose.yml file (see file) referencing the .nixpacks/Dockerfile to build one of the services.

  ## Extract of the docker-compose file referencing the nixpacks Dockerfile.
  web:
    build: 
      context: .
      dockerfile: .nixpacks/Dockerfile

Conclusion

Through this blog post, we were able to dive into the different usages of Nixpacks, see how it can help streamline the image-building process and be extended to fit any kind of workflow. You can read more about NX1, our usage of Nixpacks, and how to deploy your applications to secure environments on our Developer Guides.