Builders and Fly

What Is a Builder.

When you deploy an app on Fly, the app has to be assembled into a deployable image. That's the job that builders take on.

There are four kinds of Fly builder - dockerfile, builtins, buildpacks, and image.


The dockerfile builder is the default builder, invoked when there are no build settings in the fly.toml file. It looks for a Dockerfile in the current directory and uses that to construct the deployable image. If you are familiar with Docker, you'll be at home with this option.

This is the most flexible of the options, but with that flexibility comes the need to write Dockerfiles and the associated quirks of the Docker build system. Which is why we have the three further build options on Fly that simplify the process.


Built in to flyctl are a set of pre-configured Dockerfiles for various languages and applications. These are the builtins and you can select a language/application-specific builtin as a builder. Then, without creating any extra files, flyctl will use that builtin to build your application.

As well as being prompted with builtins when you flyctl init an application, you can also get a list of builtins with flyctl builtins list. This includes details on required files and filenames and other features of each builtin. Further details of any builtin are available with flyctl builtins show <builtinname>. This includes the virtual Dockerfile used by the builtin. If you are finding that your application has outgrown a builtin, you can copy this to a Dockerfile, remove the "build" section of fly.toml, and move to Dockerfile builds.

As of writing, there are builtins for go, node, deno, ruby, and a static web server.


Platforms like Heroku use the idea of a buildpack, a building process that's run entirely its own container, to construct their deployable images. These buildpacks are then bundled into a "builder" stack with an operating system and can be called upon to build an app. The buildpack idea has been standardized with Cloud Native Buildpacks. Buildpacks use several tests to detect if they can build the application and if they can, then proceed to run the scripts needed to create an image.

A library of standardized buildpacks are available from Paketo Buildpacks and it's from this library, Heroku's Heroku18 buildpack, and Fly's own buildpack (for Deno), that you can select from in Flyctl. If you want to use an unlisted buildpack, you can specify it by name using the --builder flag on flyctl init.

The deploy process works the same way with buildpacks, though be prepared for the deploy to error out if the buildpack doesn't detect what kind of application it's being asked to build.


Finally, if you already have a Docker image in a repository and just want to deploy that, you can skip the building process and go straight to the deploy with the image build option.

Which to choose?

For bootstrapping a project, the builtin builders offer a path of least resistance.

When you want to do something more complex or just take more control, you can quickly switch to a Dockerfile as we covered above, and customize that. Or you can also switch to buildpacks, by switching the [build] section's content to builder="buildpackname" for an automated build process which automatically configures itself.