Riding on Railway
The driving principle behind Exograph is to make it easy for developers to build their backends by letting them focus only on inherent—not incidental—complexity; Exograph should handle everything else. With Exograph, you can create a GraphQL server with a rich domain model with authorization logic, Postgres persistence, and JavaScript/TypeScript business logic in just a few lines of code. But what about deploying to the cloud?
The new platform-as-a-service offerings make deploying Exograph apps easy, and we make it easier by providing specific integrations. In this blog, I will focus on Railway. With its Postgres support and GitHub integration, you can create an Exograph server from scratch and deploy it in under three minutes!
A quick overview of Exograph
Let's take a quick look at Exograph from a deployment perspective, which will make the Railway integration easy to understand. Exograph separates the build and execution steps and ships two corresponding binaries: exo
and exo-server
.
The exo
binary Exograph's cli tool takes care of everything from building the app, migrating schema, and running integration tests to acting as a development server. It also simplifies deployment to cloud platforms, as we will see shortly.
Running an Exograph application requires that you build the app using exo build
and then run the server using exo-server
. The exo build
command processes the index.exo
file (and any files imported from it) and bundles JS/TS files. The result is an intermediate representation file: index.exo_ir
.
exo build
The exo-server
binary' is the runtime, whose sole purpose is to run Exograph apps. It processes the index.exo_ir file and runs the server.
exo-server
Please see the Exograph Architecture for more details.
These tools are available as Docker images, making it easy to integrate with cloud platforms and form the core of our Railway integration.
Railway Integration
The exo deploy railway
command generates a Docker file (Dockerfile.railway
) and railway.toml
to point to this file. The generated Docker file contains two stages:
- Build stage: Build the app and another to run it. The build stage uses the
exo
Docker image to build the app and then copies the result to the runtime stage. The stage also runs database migrations. - Runtime stage: Runs the server. It uses the
exo-server
Docker image.
Deploying to Railway then involves:
- Pushing all the code to GitHub (or using
railway up
to push the code directly to Railway) - Creating a Railway project
- Creating a Postgres service (unless you use an external Postgres)
- Creating a new service pointing to the GitHub repo (unless you use
railway up
) - Binding environment variables for the Postgres database to the service
Let's see how this works in practice.
Creating a new Exograph project
This is easy!
exo new todo
cd todo
This creates a new project with a simple todo app and initializes Git. If you are wondering, this doesn't generate much code. Here is the entire model!
@postgres
module TodoDatabase {
@access(true)
type Todo {
@pk id: Int = autoIncrement()
title: String
completed: Boolean
}
}
If you would like, you can run exo yolo
to try it out locally.
Deploying to Railway
We have a choice of using Postgres offered by Railway or an external one. Let's look at both options.
Using its Postgres
Railway offers the Postgres database service, which has the advantage of keeping both the Exograph app and the database on the same platform.
exo deploy railway --use-railway-db=true
This will generate files necessary to deploy to Railway and provide step-by-step instructions. Here is a video of the entire process: we create an Exograph project from scratch and deploy it to Railway in under three minutes.
Currently, the process involves using the dashboard to create the Postgres database and binding it to the service. We will keep an eye on Railway's tooling to make this easier. For example, if Railway supports Infrastructure-as-Code (a requested feature), we can lean on it to make the whole process in a single command.
Using Neon's Postgres
Using an external Postgres database is also easy and has the advantage of specialization offered by database providers. We will use Neon for this example.
Passing --use-railway-db=false
to exo deploy railway
will generate files for use with an external Postgres database.
exo deploy railway --use-railway-db=false
Other than using an external Postgres, the process is the same as using Railway's Postgres.
Using the playground
Following the best practice, we do not enable introspection and playground in production. But that makes working with the GraphQL server challenging. Exograph's playground solves this problem by using schema from the local model (the app's source code) and sending requests to the remote server. This way, you can explore the API without enabling introspection and playground in production.
Let us know what you think of our Railway integration. You can reach us on Twitter or Discord.