How to deploy Remix apps with SSR to AWS Amplify
Tags: aws, awsamplify, amplify, remix
Published: 2024-04-03 13:21:06

---
title: How to deploy Remix apps with SSR to AWS Amplify
published: true
date: 2024-04-02 15:00:21 UTC
tags: aws, awsamplify, amplify, remix
canonical_url: https://richdevelops.dev/how-to-deploy-remix-apps-with-ssr-to-aws-amplify
cover_image: https://cdn.hashnode.com/res/hashnode/image/upload/v1711701000624/79c3e60b-f034-4ed9-977c-c8c9ba636c07.png?w=1600&h=840&fit=crop&crop=entropy&auto=compress,format&format=webp
---

The AWS Amplify team recently announced the Amplify Hosting deployment specification. This is a way to deploy applications to AWS Amplify with server side rendering (SSR) support. While there are guides or support for many frameworks including Astro, NextJS and Nuxt I couldn't find one for Remix.

As I'm about to start working on a Shopify app (Shopify provides templates for Remix) and I didn't want to switch infrastructure providers I decided to investigate using how difficult it would be to use Amplify to host a Remix app with SSR.

The first step is to create a build file named `amplify.yml` which Amplify uses to build the project. I was deploying a new project and Amplify detected the file automatically during the initial deployment. Our build script handles four important tasks:

1. Runs `npm run build` to build the application. Remix puts the output in into the `build` folder.

2. Moves and restuctures the `build` folder output to meet the Amplify hosting specification by

3. Reduce the size of our `node-modules` folder by running `npm ci --omit dev` to create a `node-modules` that only includes production dependencies. This is important for larger project as there is a limit on the maximum size of this folder. It also helps reduce cold start times. The folder is moved into the `compute/default` folder so the modules are available at runtime.

4. Finally there are two files that we will create shortly that need to be copied into place.

The complete `amplify.yml` is below:

```
version: 1baseDirectory: .amplify-hostingfrontend: phases: preBuild: commands: - npm ci build: commands: - npm run build - mv build .amplify-hosting - mv .amplify-hosting/client .amplify-hosting/static - mkdir -p .amplify-hosting/compute - mv .amplify-hosting/server .amplify-hosting/compute/default - npm ci --omit dev - cp package.json .amplify-hosting/compute/default - cp -r node_modules .amplify-hosting/compute/default - cp server.js .amplify-hosting/compute/default - cp deploy-manifest.json .amplify-hosting/deploy-manifest.json artifacts: files: - "**/*" baseDirectory: .amplify-hosting
```

AWS Amplify will now package and deploy our `.amplify-hosting` folder.

The `deploy-mainfest.json` has two main tasks:

1. Tell Amplify how to route traffic

2. Tell Amplify how to configure and start the compute resources

This routing should not be confused with rewriting and redirecting traffic. It's purpose is to indicate if traffic should be handled as static or compute. Here I'm using the less than perfect approach that files with a `.` should be treated as static first and fall back to compute if they don't exist. Everything else should be treated as compute. This means that static files must have a `.` in the filename.

For the compute configuration I've set the runtime to Node 20 and the project should be started by using `node server.js`

The full `deploly-mainfest.json` is:

```
{ "version": 1, "framework": { "name": "remix", "version": "2.8.1" }, "routes": [{ "path": "/*.*", "target": { "kind": "Static", "cacheControl": "public, max-age=2" }, "fallback": { "kind": "Compute", "src": "default" } }, { "path": "/*", "target": { "kind": "Compute", "src": "default" } }], "computeResources": [{ "name": "default", "runtime": "nodejs20.x", "entrypoint": "server.js" }]}
```

Finally I need to create a small Javascript file called `server.js`. This file launches an Express server on port 3000 which listens for requests and passes them to Remix. Remember to add express as a production dependency so this will work.

```
npm i express --save
```

The complete server.js is:

```
import remix from "@remix-run/express";import express from "express";import * as build from "./index.js";const app = express();const port = 3000;app.all( "*", remix.createRequestHandler({ build, }));app.listen(port, () => { console.log(`Example app listening on port ${port}`)})
```

That's it! You should be able to deploy the project to AWS Amplify and when you go to the URL provided your request will be execute on the server.