Deploying a Self-Hosted Expo API Routes using Docker
Learn how combining Expo with libSQL enhances app performance and speeds up load times.
Last edited: Mon Oct 28 2024
Expo API Routes were introduced with Expo 50, and it's a feature that is still not well-known.
New developers tend to miss the power of this feature.
Expo Routes introduce page navigation similar to Next.js but can also create server endpoints and REST API in WinterGC-compliant environment.
In other words, you can write a GET/POST/PUT/PATCH/DELETE routes that can handle server logic in the same app folder!
With Server Side Rendering comming to Expo 52 in the next release, hosting will be crucial to make your app performant and scalable.
Let’s dive into how to use Expo Routes to create a custom API endpoint that we can use in our app:
First, let’s set the output of the bundler to a server instead of static. This will generate server code as well as a static web app for your Expo project:
Let’s create our first REST API. Inside the app project folder, a file with +api.ts will be treated as a route API and should export POST, GET functions to handle the request:
Here we just parse the body and return it as a response:
Note that this will only work for the web since it runs on the same host. For production, you should set the origin for expo-router in the app.json file:
Next, let’s export our project. This command will bundle all the functions and static files into a single dist folder:
This will generate a dist directory with client and server.
Expo documentation provides a server script based on Express.js that can serve the exported project:
You should be able to run the server locally with:
You can host the project by just copying the dist and server.js and hosting it on any server manually.
But, let's use Docker to make a nice container that we can deploy anywhere:
With this Dockerfile, you can generate a compact version of your project, which will contain both the static web version of your mobile app and also the backend API:
Running the container should be straightforward too:
With this approach, you can implement both the mobile app and its backend dependencies in one place, generating a nice container to be deployed anywhere. No need to create a separate project whose only purpose is to provide your backend for your mobile app.