Skip to main content

Fly.io

Let's deploy our application to Fly.io, which has an excellent user experience. You can adapt this tutorial for other cloud providers that support Docker.

We will use two Postgres providers:

  • Fly.io: This allows us to work with a single cloud provider. However, the Postgres provided by Fly.io is not a managed database, which puts the onus on you to keep its image updated, etc.
  • External: We will illustrate using Neon, a "multi-cloud fully managed Postgres with a generous free tier". The basic steps will remain the same if you want to use other Postgres providers.

Installing the prerequisites

You need to install Flyctl.

Creating a new application

Let's start from scratch to keep this tutorial standalone. However, you can also use an existing application like the concert management application developed in the Application Tutorial guide.

Let's create a new application:

exo new todo
cd todo

The exo deploy fly command

Exograph has a dedicated command to work with Fly.io. It will:

  • Configure a fly.toml file
  • Create two Docker files: Dockerfile.fly and Dockerfile.fly.builder (the latter is used to simplify secrets management)
  • Provide deployment instructions

It offers several options to customize the deployment, and you can learn more by running exo deploy fly --help.

exo deploy fly --help
Deploy to Fly.io

Usage: exo deploy fly [OPTIONS] --app <app-name> [model]

Arguments:
[model] The path to the Exograph model file. [default: index.exo]

Options:
-a, --app <app-name> The name of the Fly.io application to deploy to
-e, --env <env> Environment variables to pass to the application (e.g. -e KEY=VALUE). May be specified multiple times.
--env-file <env-file> Path to a file containing environment variables to pass to the application
--use-fly-db Use database provided by Fly.io
-h, --help Print help

Setting up

From the application's directory, run the following command:

We want to use the Postgres database provisioned on Fly.io, hence we pass the --use-fly-db option.

exo deploy fly --app todo --use-fly-db
CORS

If you intend to consume the API through a web application, you would need to set CORS domains by passing -e EXO_CORS_DOMAINS=<comma-separated-domains> to exo deploy fly or changing the generated fly.toml file.

The command creates a fly.toml file in the current directory. You can edit it to customize the deployment. For example, you can change the number of instances, the regions, etc. See the Fly.io documentation for more details.

Similarly, it creates a Dockerfile.fly in the current directory. You can edit it to customize the Docker image. For example, you can add more dependencies, set up the timezone, etc. See the Docker documentation for more details. It also creates Dirverfile.fly.builder to simplify secrets management (see Fly secret management for more information). You are unlikely to edit it.

It also gives a step-by-step guide to deploying the application. We will follow those instructions.

Deploying the app

Let's follow the instructions.

Create the app

The first command will create the app in Fly.io. When presented with the option to select an organization, select an appropriate one.

fly apps create todo
? Select Organization: <your account name>
New app created: todo

Set the JWT secret or the OIDC URL

Fly.io offers a secret vault for sensitive information like the JWT secret (you should not use an environment variable for such values). We will use it to store authentication-related secrets. In the command below, replace <your-jwt-secret> with your own.

fly secrets set --app todo EXO_JWT_SECRET=<your-jwt-secret>
Secrets are staged for the first deployment

Alternatively, you can use an OIDC URL. In the command below, replace <your-oidc-url> with your own.

fly secrets set --app todo EXO_OIDC_URL=<your-oidc-url>
Secrets are staged for the first deployment

Create the database

Since we opted to use the Fly.io database, let's create one:

fly postgres create --name todo-db

Attach the database to the app

The next step attaches the database to the app, which creates the database instance and the user for the app.

fly postgres attach --app todo todo-db

Deploy the app

Finally, we follow the suggested command to deploy the app:

flyctl console --dockerfile Dockerfile.fly.builder -C "/srv/deploy.sh" --env=FLY_API_TOKEN=$(flyctl auth token)

This command creates an ephemeral container, which deploys the Docker image to Fly.io. See Fly.io documentation for more details.

At the end of the deployment, you will see a message like this:

Visit your newly deployed app at https://exo-concerts.fly.dev/
Waiting for ephemeral machine 1781109ec04128 to be destroyed ... done.

Testing the app

Since we didn't set the EXO_INTROSPECTION environment variable, it will be false by default, which is a good practice in production. This default makes the GraphQL playground unavailable with the production URL. Thanks to exo playground command, this is not a problem. Run the following command to open the playground:

exo playground --endpoint https://<server-url>/graphql

This will print a URL to the playground. Open it in your browser. You should see the playground.

Starting playground server connected to the endpoint at: https://<server-url>/graphql
- Playground hosted at:
http://localhost:9876/playground

Now open http://localhost:9876/playground to see the GraphiQL Playground. You can execute queries and mutations. See the Getting Started guide for more details.

tip

Run the fly logs command to see the app's logs. Note that the most significant factor for execution speed will be the regions in which your app and database are deployed. If they are in the same region, the latency will be smaller.