Configuration and fly.toml

All Fly applications have a fly.toml file which describes how the application should be configured when it is deployed onto the Fly platform. This configuration includes the application name, builder to be used (optional), ports, services and handlers to set up and parameters for health checks.

The file is in TOML format (github reference). If you are unfamiliar with TOML, here's a useful introduction. It is made up of lines with either key/value settings or sections (noted by values surrounded by one or more pairs of square brackets).

You don't need to create a fly.toml file by hand. Running flyctl init generates one for you, interactively prompting you for various values.

Fly.toml - line by line

The app name

The first key/value in any fly.toml file is the application name. This will also be used to create the host name that the application will use by default. For example:

app = "restless-fire-6276"

Whenever flyctl is run, it will look for a fly.toml file in the current directory and use the application name in that file. This behavior can be overridden by using the -a flag to set the application name, or on some commands (such as deploy) by using a -c flag to point to a different fly.toml file.

The build section

The optional build section contains key/values concerned with how the application should be built. You can read more about builders in Builders and Fly

There are then four possible settings for builders in the build section of fly.toml:

  • builtin
  • builder
  • image
  • dockerfile


  builtin = "node"

The builtin builder setting makes flyctl use one of the integrated builders. These are available for go, node, deno, ruby and static (web server). They are designed for quick deployments with minimal fuss. When running flyctl init, you are offered a chance to select from the available builtins or you can specify flyctl init --builtin node to preselect the node builtin.


  builder = ""

The builder "builder" uses CNB Buildpacks and Builders to create the application image. These are third party toolkits which can use Heroku compatible build processes or other tools. The tooling is all managed by the buildpacks and buildpacks are assembled into CNB Builders - images complete with the buildpacks and OS to run the tool chains.

A selection of recommended buildpacks is offered when running flyctl init. If you want a buildpack builder that is not listed, run fly init time and use --builder buildername in the command line.

In our example above, the builder is being set to use Google's all-purpose buildpack. To learn more about buildpacks and Fly, refer to this blog posting Simpler Fly deployments for NodeJS, Rails, Go, and Java.


  image = "flyio/hellofly:latest"

The image builder is used when you want to immediately deploy an existing public image. When deployed, there will be no build process; the image will be prepared and uploaded to the Fly infrastructure as it. This option is useful if you already have a working Docker image you want to deploy on Fly or you want a well known Docker image from a repository to be run.

When running flyctl init add --image imagename to the command line to get this option configured - it is not available for interactive selection.


Not really a particular setting, more the default. If there is no build section, flyctl will look for a Dockerfile to use to build the app image.

The services section

The services section configures the mapping of ports on the application to ports and services on the Fly platform. These mappings determine how connections to the application will be handled on their journey from the Fly edge network to running Fly applications.

Services is a table of tables in TOML, so the section is delimited with double square brackets, like this:

  internal_port = 8080
  protocol = "tcp"
  • internal_port : The port the application will use to communicate with clients. The default is 8080. We recommend applications use the default.
  • protocol : The protocol that the application will use to communicate.


The services concurrency sub-section configures the applications behavior with regard to concurrent connections and compute scaling. It is a simple list of key/values, so the section is denoted with single square brackets like so:

    hard_limit = 25
    soft_limit = 20
  • hard_limit : When an application instance is at or over this number of concurrent connections, the system will bring up another instance.
  • soft_limit : When an application instance is at or over this number of concurrent connections, the system is likely bring up another instance.


For each external port you want to accept connections on, you will need a services.ports section. One for each port, the section is denoted by double square brackets like this:

    handlers = ["http"]
    port = "80"

This example defines an HTTP handler on port 80.

  • handlers : An array of strings, each string selecting a handler process to terminate the connection with at the edge. Here, the "HTTP" handler will accept HTTP traffic and pass it on to the internal port of the application which we defined earlier.
  • port : A string which selects which external ports you want Fly to accept traffic on. You can configure an application to listen for global traffic on ports 80, 443, 5000, and ports 10000 - 10100.

You can have more than one services.ports sections. The default configuration, for example, contains two. We've already seen one above. The second one defines an external port 443 for secure connections, using the "tls" handler.

    handlers = ["tls", "http"]
    port = "443"

The details of how these handlers manage network traffic, and other handlers available, are detailed in the Network Services documentation.


When a service is running, the Fly platform checks up on it by connecting to a port. The services.tcp_checks section defines parameters for those checks. For example, the default tcp_checks look like this:

    interval = 10000
    timeout = 2000
  • interval: The time in milliseconds between connectivity checks.
  • timeout: The maximum time a connection can take before being reported as failing its healthcheck.


Another way of checking a service is running is through HTTP checks as defined in the services.http_checks section. These checks are more thorough than tcp_checks as they require not just a connection but a successful HTTP status in response (i.e, 2xx). Here is an example of a services.http_checks section:

    interval = 10000
    method = "get"
    path = "/"
    protocol = "http"
    timeout = 2000
    tls_skip_verify = false

Roughly translated, this section says every ten seconds, perform a HTTP GET on the root path (e.g. looking for it to return a HTTP 200 status within two seconds. The parameters of a http_check are listed below.

  • interval: The time in milliseconds between connectivity checks.
  • method: The HTTP method to be used for the check.
  • path: The path of the URL to be requested.
  • protocol: The protocol to be used (http or https)
  • timeout: The maximum time a connection can take before being reported as failing its healthcheck.
  • tls_skip_verify: When true (and using HTTPS protocol) skip verifying the certificates sent by the server.
  • services.http_checks.headers: This is a sub-section of services.http_checks. It uses the key value pairs as a specification of header and header values that will get passed with the http_check call.

Note: The services.http_checks section is optional and not generated in the default fly.toml file.