LogoFreestyle

Deploying Expo Projects

How to deploy an Expo Project to Freestyle

Expo is a framework for building cross-platform mobile apps. While primarily used to create iOS and Android Apps, these apps can also be compiled to static websites and hosted on Freestyle. This guide will walk you through the process of configuring and deploying an Expo app to Freestyle. This guide shows you how to deploy a Static or SPA Expo app. If you want to deploy a server-side rendered Expo app, the general same steps should apply, except for the server implementation.

Setup

If you don't have a pre-existing Expo app, run the command below to initialize it. It'll ask you where to put the app, for the purposes of this guide I'll be putting it in my-app

npx create-expo-app@latest

Once you've created the app, install the dependencies necessary for shipping it to website. react-dom is necessary for React to render on the web, react-native-web is for React Native to compile its components to html, and @expo/metro-runtime is for Expo to be able to compile it's structures to web.

npx expo install react-dom react-native-web @expo/metro-runtime

Now you have an expo app ready to be deployed.

Deploying the App

Get your API key from the Freestyle dashboard, and create a .env file with the following content:

FREESTYLE_API_KEY=your-api-key

Install the Freestyle Sandboxes Client

npm i freestyle-sandboxes

Now you need a script to deploy the app. This is an example script that deploys the app.

It first creates a FreestyleSandboxes client with your Freestyle API Key. then it calls .deployWeb with two options: source + configuration.

source is an object of files to their file contents, you can write a custom function that takes your directory and prepares it for uploading, however we provide a series of utilities making it easy.

configuration comes with anything other than the code you want to configure, that might be the domains, the entrypoint, the environment variables, or the network permissions.

deploy.ts
import { FreestyleSandboxes } from "freestyle-sandboxes";
import { prepareDirForDeploymentSync } from "freestyle-sandboxes/utils";

// Create a sandboxes client
const sandboxes = new FreestyleSandboxes({
  apiKey: process.env.FREESTYLE_API_KEY!,
});

async function deploy() {
  await sandboxes.deployWeb(prepareDirForDeploymentSync("."), {
    domains: ["example.style.dev"],
    build: true, // This automatically detects the framework and configures/builds for you
  });
}

deploy();

Finally, to make the deploy happen, run it

bun run deploy.ts

Preparing the App for Deployment

We run the command below to create a production build of your app for web.

npx expo export --platform web

Now, we slightly modify the output so that it works with freestyle module resolution by changing the dists node_modules folder to modules. Freestyle doesn't support uploading node_modules as we have a special carveout for caching them, however expo build outputs a directory called dist/assets/node_modules which we can rename to dist/assets/modules so it will work.

This is an example way to do it

find dist -type f -name "*.js" -exec sed -i '' 's/node_modules/modules/g' {} +
mv dist/assets/node_modules dist/assets/modules

Creating a Server

By default, Expo outputs only static files. In order to serve them on Freestyle, we create a simple server using Hono, a lightweight web framework for Deno. This server will serve the static files generated by Expo.

First install hono

npm i hono

Then you can use the following code to serve the files.

main.ts
import { Hono } from "hono";
import { serveStatic } from "hono/deno";

const app = new Hono();

app.use("*", serveStatic({ root: "./dist" }));

// fallback to index.html
app.get("*", serveStatic({ path: "./dist/index.html" }));

Deno.serve(app.fetch);

This setup works for both the expo output configurations of "output": "single" and "output": "static", for "output": "server", use the server entrypoint instead of creating a custom one.

If you want to run expo in server mode, with support for Expo API Routes, you can set the output to server in your app.json file.

{
  "expo": {
    "web": {
      "bundler": "metro",
      "output": "server"
    }
  }
}

Then, you'll need to create a simple entrypoint to run the server. Freestyle provides first class support for Expo server mode:

main.ts
import { freestyleExpoServer } from "freestyle-sandboxes/expo";

freestyleExpoServer();

By default, this expects the output to be in the dist folder, but you can override where the server and client files it pulls from are by passing the options object to freestyleExpoServer.

Deploying the App

CLI

Install the Freestyle CLI.

npm i freestyle-sh

Now deploy it

npx freestyle deploy --domain some.style.dev --web main.ts

API

You can also deploy the app using the API.

Get your API key from the Freestyle dashboard, and create a .env file with the following content:

FREESTYLE_API_KEY=your-api-key

Install the Freestyle Sandboxes Client

npm i freestyle-sandboxes

Now you need a script to deploy the app. This is an example script that deploys the app.

It first creates a FreestyleSandboxes client with your Freestyle API Key. then it calls .deployWeb with two options: source + configuration.

source is an object of files to their file contents, you can write a custom function that takes your directory and prepares it for uploading, however we provide a series of utilities making it easy.

configuration comes with anything other than the code you want to configure, that might be the domains, the entrypoint, the environment variables, or the network permissions.

deploy.ts
import { FreestyleSandboxes } from "freestyle-sandboxes";
import { prepareDirForDeploymentSync } from "freestyle-sandboxes/utils";

// Create a sandboxes client
const sandboxes = new FreestyleSandboxes({
  apiKey: process.env.FREESTYLE_API_KEY!,
});

async function deploy() {
  await sandboxes.deployWeb(prepareDirForDeploymentSync("."), {
    entrypoint: "main.ts",
    // put whatever domains you want here
    domains: ["example.style.dev"],
  });
}

deploy();

Finally, to make the deploy happen, run it

bun run deploy.ts

Next Steps

Now that you can deploy Expo apps to Freestyle, you'll probably want to deploy them to custom domains. To deploy to your own custom domains, you can use the UI in the Freestyle dashboard, and to start building self serve to deploy to your users domains you should check out this guide