Idiomatic Remix apps can generally be deployed anywhere because Remix adapts the server's request/response to the Web Fetch API. It does this through adapters. We maintain a few adapters:
@remix-run/architect
@remix-run/cloudflare-pages
@remix-run/cloudflare-workers
@remix-run/express
These adapters are imported into your server's entry and are not used inside your Remix app itself.
If you initialized your app with npx create-remix@latest
with something other than the built-in Remix App Server, you will note a server/index.js
file that imports and uses one of these adapters.
Each adapter has the same API. In the future we may have helpers specific to the platform you're deploying to.
@fastly/remix-server-adapter
— For Fastly Compute.@mcansh/remix-fastify
— For Fastify.@mcansh/remix-raw-http
— For a good old bare-bones Node.js server.@netlify/remix-adapter
— For Netlify.@netlify/remix-edge-adapter
— For Netlify Edge.@vercel/remix
— For Vercel.remix-google-cloud-functions
— For Google Cloud and Firebase functions.partymix
— For PartyKit.@scandinavianairlines/remix-azure-functions
— For Azure Functions and Azure Static Web Apps.createRequestHandler
Creates a request handler for your server to serve the app. This is the ultimate entry point of your Remix application.
const { createRequestHandler, } = require("@remix-run/{adapter}"); createRequestHandler({ build, getLoadContext });
Here's a full example with express:
const { createRequestHandler, } = require("@remix-run/express"); const express = require("express"); const app = express(); // needs to handle all verbs (GET, POST, etc.) app.all( "*", createRequestHandler({ // `remix build` and `remix dev` output files to a build directory, you need // to pass that build to the request handler build: require("./build"), // Return anything you want here to be available as `context` in your // loaders and actions. This is where you can bridge the gap between Remix // and your server getLoadContext(req, res) { return {}; }, }) );
Here's an example with Architect (AWS):
const { createRequestHandler, } = require("@remix-run/architect"); exports.handler = createRequestHandler({ build: require("./build"), });
Here's an example with the simplified Cloudflare Workers API:
import { createEventHandler } from "@remix-run/cloudflare-workers"; import * as build from "../build"; addEventListener("fetch", createEventHandler({ build }));
Here's an example with the lower-level Cloudflare Workers API:
import { createRequestHandler, handleAsset, } from "@remix-run/cloudflare-workers"; import * as build from "../build"; const handleRequest = createRequestHandler({ build }); const handleEvent = async (event: FetchEvent) => { let response = await handleAsset(event, build); if (!response) { response = await handleRequest(event); } return response; }; addEventListener("fetch", (event) => { try { event.respondWith(handleEvent(event)); } catch (e: any) { if (process.env.NODE_ENV === "development") { event.respondWith( new Response(e.message || e.toString(), { status: 500, }) ); } event.respondWith( new Response("Internal Error", { status: 500 }) ); } });