How To Dockerize Remix Apps 💿🐳
Tags: docker, devops, beginners, webdev
Published: 2024-06-12 13:50:43

Dockerizing your Remix app is straightforward and makes your app independent of hosting providers! Let's get to it and build a production ready Dockerfile! 🤘🗿
## Basic Dockerfile

To get started, let's create a basic Dockerfile for our Remix app:

```Dockerfile
FROM node:21-bullseye-slim
WORKDIR /myapp
ADD . .
RUN npm install
RUN npm run build
CMD ["npm", "start"]
```

Make sure to change the command to match your start script if it differs from npm start. You can then build it like this:

```bash
docker build -t remix-minimal .
```

## Improvements

As always with Docker, you can improve your Docker image in a few easy ways. Let's look at the two most obvious ways: copying only what you need (improving caching!) and multi-stage builds (improving the image size!) 🚀

### Copying Only What You Need
A lot of the time your docker build takes comes from expensive I/O operations or the inability to cache single steps of your build process.

#### .dockerignore 🤷

Firstly, create a .dockerignore file with everything that you do not want in your Docker image. This usually includes stuff like your node_modules, compiled files, or documentation. Simply write the folder names that you want to be ignored in a file, or copy an existing one.

```plain
node_modules
README.md
LICENSE
.env
```

### Separate Copy Steps

If you are actively developing your app and you need to constantly rebuild your Docker Image, chances are that your code changes a lot more than your dependencies. You can profit from that fact by separating the install and build steps. Docker will then only re-install your dependencies if they actually changed! 🥳

```Dockerfile
FROM node:21-bullseye-slim
WORKDIR /myapp

### Copy the lock and package file

ADD package.json .npmrc ./

### Install dependencies

RUN npm install --include=dev

### Copy your source code

### If only files in the src folder changed, this is the only step that gets executed!

ADD . .

RUN npm run build && npm prune --omit=dev

CMD ["npm", "start"]
```

### Multi-Stage Builds

If you want to be a bit fancier or you need a smaller Docker image, you can also use multi-stage builds. This reduces the final image size by only including necessary runtime dependencies.

We'll take the Dockerfile from the previous step as the template but extend it to use multi-stage builds. We'll build the app in one stage and use a smaller base image for the final stage.

```Dockerfile
# base node image

FROM node:21-bullseye-slim as base

# set for base and all layer that inherit from it

ENV NODE_ENV production

# Install all node_modules, including dev dependencies

FROM base as deps

WORKDIR /myapp

ADD package.json .npmrc ./
RUN npm install --include=dev

# Setup production node_modules

FROM base as production-deps

WORKDIR /myapp

COPY --from=deps /myapp/node_modules /myapp/node_modules
ADD package.json .npmrc ./
RUN npm prune --omit=dev

# Build the app

FROM base as build

WORKDIR /myapp

COPY --from=deps /myapp/node_modules /myapp/node_modules

ADD . .
RUN npm run build

# Finally, build the production image with minimal footprint

FROM base

WORKDIR /myapp

COPY --from=production-deps /myapp/node_modules /myapp/node_modules

COPY --from=build /myapp/build /myapp/build
COPY --from=build /myapp/public /myapp/public
ADD . .

CMD ["npm", "start"]
```

## Credits

The Dockerfile is based on one of the [official Remix stacks](https://github.com/remix-run/blues-stack/blob/main/Dockerfile)! 

## Next Steps

How was your experience developing and deploying your Remix app? I've really enjoyed it so far, although there is still a lot of work to do to make it truly great. I'd love to hear your opinions!

**If you want to go further, check out [Sliplane](https://sliplane.io?utm_source=dockerizeremix) to deploy all your dockerized apps!**