Remix on Vercel is surprisingly difficult to get right because Vercel’s default build process often strips out essential server-side code.
Let’s see a typical Remix app deployed to Vercel, focusing on the serverless function.
remix.config.js
/** @type {import('@remix-run/dev').RemixConfig} */
module.exports = {
serverBuildTarget: "vercel", // Crucial for Vercel deployment
ignoredRouteFiles: ["**/.*"],
// ... other config options
};
vercel.json
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/remix"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "/index.html" // Default for static assets
},
{
"src": "/(.*)",
"dest": "/server/$1" // Points to the serverless function
}
]
}
This setup tells Vercel to use its @vercel/remix build image, which is optimized for Remix. The routes section is key: it defines how incoming requests are handled. Static assets (like your public/ directory contents) are served directly, while all other requests (/(.*)) are routed to the Remix serverless function, specified here as /server/$1. The $1 captures the requested path and passes it to your server.
The Problem:
The core challenge with deploying Remix serverlessly is that your server code needs to run in a Node.js environment, but Vercel’s build process, especially without specific configuration, might try to bundle everything into static assets or a client-side-only bundle. This means your server-side rendering (SSR) logic, API routes, and form submission handlers could fail because the server code never actually gets executed.
The serverBuildTarget: "vercel" Setting:
This is the most critical piece of configuration for Vercel. In your remix.config.js, setting serverBuildTarget: "vercel" tells the Remix build process to output a build specifically tailored for Vercel’s serverless environment. It generates a server/index.js (or similar) file that Vercel can then deploy as a serverless function. Without this, Remix might default to a node target, which isn’t directly compatible with Vercel’s serverless functions without further adaptation.
vercel.json for Serverless Functions:
The vercel.json file is Vercel’s way of configuring your deployment. The builds section specifies which build image to use. For Remix, @vercel/remix is the recommended image as it understands how to build and deploy Remix applications correctly. The routes section is where you define routing rules. For a Remix app, you’ll typically have a route that directs all requests to your serverless function. The example above uses "/server/$1" as the destination, which assumes your serverless function is located at server/index.js and will handle requests for any path.
Environment Variables:
Your Remix app likely relies on environment variables for API keys, database connections, etc. Vercel allows you to configure these in your project settings under "Environment Variables." Ensure that any variables used in your server-side code are correctly set in Vercel. If you’re using process.env.NODE_ENV, Vercel sets this to production automatically.
Database Connections:
If your Remix app connects to a database, the connection logic must reside in your server-side code. When deploying to Vercel’s serverless functions, you’ll need to establish these connections within the function’s execution context. This often means using connection pooling and ensuring that connections are properly managed across function invocations. Libraries like prisma or pg will work, but you need to instantiate them within your server code.
Catch-all Routes and Serverless Functions:
Remix’s catch-all routes (e.g., app/routes/$slug.tsx) are handled by the serverless function. When a request comes in for /posts/my-first-post, Vercel routes it to your serverless function, which then invokes the appropriate Remix loader or action for that route. The vercel.json configuration ensures this routing happens seamlessly.
Deployment Workflow:
- Install Vercel CLI:
npm install -g vercel - Link Project: Run
vercel linkin your project’s root directory and follow the prompts to connect to your Vercel project. - Deploy: Run
vercelfor a preview deployment orvercel --prodfor a production deployment. Vercel will build your Remix app using the@vercel/remixbuilder and deploy the serverless function.
The One Thing Most People Don’t Know:
Vercel’s @vercel/remix builder is more than just a wrapper; it actively optimizes your Remix build for the serverless environment by intelligently separating client-side code from server-side code and configuring the output for efficient cold starts. It also handles the creation of the bootstrap.js file that Vercel uses to invoke your Remix server function, abstracting away a lot of the low-level serverless deployment details that you’d otherwise have to manage manually.
The next thing you’ll likely encounter is optimizing function cold starts for a better user experience.