slew docs/runtimes/remix

Deploying Remix

Remix runs on slew's Node servers. The platform starts your app as node <entry> — it doesn't run package binaries, so remix-serve is out; either let the git builder generate a server around your build (the default path), or bundle a small server yourself.

Push to GitHub — detected automatically

Connect the repo and every push deploys. The builder recognizes a Remix build — @remix-run/node in dependencies (every Remix template has it) plus build/server/index.js — and assembles the server artifact for you: a generated node:http server around build/server, a production node_modules from your lockfile (npm ci --omit=dev, so commit a package-lock.json), and build/client/ served straight from the CDN. Leave the build settings at their defaults:

slew git connect owner/repo

PORT is injected by the platform; the generated server binds 0.0.0.0. Keep production dependencies lean — the deploy caps at 10,000 files, node_modules included.

Bundle it yourself (works with slew deploy too)

An explicit slew.json in the output directory always wins over detection. Bundling the server with esbuild makes the entry self-contained — no node_modules in the artifact, so it deploys through both slew deploy and git builds.

npm i express @remix-run/express

server.mjs:

import { createRequestHandler } from '@remix-run/express'
import express from 'express'

const app = express()
app.use(createRequestHandler({ build: await import('./build/server/index.js') }))
app.listen(process.env.PORT ?? 3000, '0.0.0.0')

Client assets don't need express.static: they ship in static/ and the CDN serves them before your server is ever involved.

npm run build        # remix vite:build
npx esbuild server.mjs --bundle --platform=node --format=esm --outfile=out/server/index.mjs
mkdir -p out/static && cp -r build/client/. out/static/
printf '{ "server": "server/index.mjs" }\n' > out/slew.json
slew.json            { "server": "server/index.mjs" }
server/index.mjs     server.mjs + the Remix server build + dependencies, in one file
static/              = build/client — served directly by the CDN

If a dependency won't survive esbuild's ESM bundling (native addons, dynamic require), skip the bundling and ship node_modules inside server/ via git push-to-deploy instead — same layout as the SvelteKit recipe.

Deploy:

slew init
slew deploy out

Or connect the repo with the assembly steps as the build command:

slew git connect owner/repo --build-cmd "npm run build:slew" --output out

Fingerprinted assets under /assets/* come from the CDN; every other request — including all non-GET — reaches the server, and Remix owns its routing and 404s.