Expo Router Server API
expo-server is a foundational server-side API and runtime library specifically designed for projects leveraging Expo Router. It provides essential utilities and adapters for implementing server-side logic, including API routes, server-side rendering (SSR), and React Server Components (RSC) within a universal Expo application. Functioning primarily in a WinterCG-compliant environment, it allows developers to define API endpoints using a file-based convention (e.g., `+api.ts`), handle HTTP requests, and manage sensitive data securely on the server. The package facilitates full-stack development within the Expo ecosystem, enabling consistent codebases across native, web, and server environments. Expo SDK, which this package is part of or closely aligned with, typically releases new major versions three to four times a year. The current stable version of the broader Expo SDK is 55.x.x, with `expo-server` itself having independent, though generally aligned, releases (e.g., 0.7.5 as seen on npm for `@expo/server`). A key differentiator is its tight integration with Expo Router's opinionated file-system routing and universal development paradigm.
Common errors
-
Error: require is not defined in ES module scope
cause Attempting to use CommonJS `require()` syntax in an Expo Router API route or other server module, which are typically ESM.fixRefactor imports to use ES module `import` syntax (e.g., `import { someFunction } from 'some-package';`). -
405 Method Not Allowed
cause An API route was called with an HTTP method that is not explicitly exported by the `+api.ts` file (e.g., calling a `POST` route when only `GET` is exported).fixEnsure that the corresponding HTTP method (e.g., `export function POST(request: Request) { ... }`) is defined and exported in your `+api.ts` file for the method you are using. -
Failed to fetch /your-api-route (or similar network error in native builds)
cause The native application cannot resolve the API route URL, typically because the `origin` is not correctly configured for production deployments, or `web.output: "server"` is missing.fixVerify `web.output: "server"` is set in `app.json`. For production native builds, set `"expo": { "extra": { "router": { "origin": "https://your-deployed-server.com" } } }` in your `app.json`. -
Property 'push' does not exist on type 'Omit<Router, "navigate">' (or similar TypeScript error with router methods)
cause You are using `expo-router`'s navigation functions (like `router.push`) but haven't enabled or correctly configured typed routes, or are trying to access server-only types in a client context.fixRun `npx expo customize tsconfig.json` and ensure you start the development server (`npx expo start`) to generate typed routes. Make sure your `tsconfig.json` includes `expo-router/tsconfig.json`.
Warnings
- breaking For Expo Router API routes and server-side features to function correctly, you must configure `"web": { "output": "server" }` in your `app.json` or `app.config.js` file. Omitting this will prevent server bundles from being generated.
- gotcha The runtime APIs exposed by `expo-server` (e.g., `origin`, `environment`, `runTask`, `deferTask`) are strictly for server-side code. Attempting to use them in client-side bundles will result in runtime errors.
- gotcha When deploying Expo Router API routes to production or native builds, especially to third-party services, you often need to explicitly set the `origin` property in your `app.json` or `app.config.js` to the deployed server's URL. In development, it automatically points to the dev server.
- gotcha Environment variables behave differently on the server vs. client. Server routes (e.g., `+api.ts`) have access to all environment variables, while client-side code only has access to those prefixed with `EXPO_PUBLIC_`.
- deprecated React Server Components (RSC) support in Expo Router, while powerful, is still considered experimental or in beta. APIs may be subject to breaking changes without major SDK version bumps, and some traditional React features (hooks, state, browser APIs) are not available in RSCs.
Install
-
npm install expo-server -
yarn add expo-server -
pnpm add expo-server
Imports
- origin
const { origin } = require('expo-server');import { origin } from 'expo-server'; - environment
import { ENVIRONMENT } from 'expo-server';import { environment } from 'expo-server'; - createRequestHandler
import { createRequestHandler } from 'expo-server';import { createRequestHandler } from 'expo-server/adapter/http';
Quickstart
/* app.json */
{
"expo": {
"web": {
"output": "server"
}
}
}
/* src/app/hello+api.ts */
// Ensure your project has 'web.output': 'server' in app.json for API routes to be bundled.
import { environment, origin } from 'expo-server';
export async function GET(request: Request) {
const url = new URL(request.url);
const name = url.searchParams.get('name') || 'world';
console.log(`API Call received from origin: ${origin()}`);
console.log(`Running in environment: ${environment()}`);
return Response.json({
message: `Hello, ${name}! This is a server-side API route.`,
isProduction: environment() === 'production',
currentOrigin: origin()
});
}
// To test, run `npx expo start` and then navigate to `http://localhost:8081/hello` or `http://localhost:8081/hello?name=Alice` in your browser or a tool like curl.
// In a native app, you would fetch from `/hello` and Expo Router would correctly proxy it to the server.