How to deploy a nestjs back-end from a mono repo on fly.io
Tags: nestjs, webdev, beginners, tutorial
Published: 2024-04-28 12:41:44

I recently had to deploy an API backend from a monorepo on fly.io and this is a documentation of the steps.
The project uses turborepo with npm managed workspace. The monorepo had the below structure 
![Monorepo Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x74yvrugxz02cw2d248z.PNG)

Fly.io has a generous free tier that is perfect for small projects like MVPs. New users get a $5 credit which gives up to 3 shared-cpu-1x 256mb VMs and 3GB persistent volume storage. This served my purposes especially during development. Let's dive in.

### Step 1: Create an Account on fly.io & Install Fly CLI
To begin visit [fly.io](https://fly.io/) to create an account. Next install flyctl a command line tool for creating and deploying fly apps.
**macOS** 
```
brew install flyctl
```
**Windows**
```
pwsh -Command "iwr https://fly.io/install.ps1 -useb | iex"
```
You may have to run the command on windows with `powershell` instead of `pwsh` if you run into errors. Full instructions can be found [here](https://fly.io/docs/hands-on/install-flyctl/). After installation authenticate the CLI using:
```
fly auth login
```
### Step 2: Create A Dockerfile
Flyctl automatically detects a Dockerfile in the app root directory, it builds an image from it and deploys containers from the image.
Create a Dockerfile in the nestjs app's root directory and paste in the following content. 
```
# Line 1
FROM node:20-alpine as builder
# Line 2
ENV NODE_ENV build
# Line 3
WORKDIR /api
# Line 4
COPY package*.json ./
# Line 5
RUN npm install
# Line 6
COPY . .
# Line 7
RUN npm run build \
    && npm prune --production

# Line 8
FROM node:20-alpine
# Line 9
ENV NODE_ENV production
# Line 10
WORKDIR /api
# Line 11
COPY --from=builder  /api/package*.json ./
COPY --from=builder  /api/node_modules/ ./node_modules/
COPY --from=builder  /api/dist/ ./dist/
# Line 12
CMD ["node", "dist/src/main.js"]
```
This dockerfile uses a multi stage build, which is a docker build process that lets you build an image in multiple stages. Each build stage has output(files) from which one can copy only what is needed to the next build stage. This removes unnecessary files like development dependencies from the final output which helps to reduce the overall size of the resulting image.

In the **builder** stage(Line 1), from Lines 4-7, we copy package.json file to the image, run the install script, copy over the generated files and build the nest app.

In the next stage of the build (beginning on line 8), in Line 11 we copy package.json and lock files, node modules folder and dist folder(output of 'npm run build') to the image and on line 12 we finally specify the start command.

### Step 3: Create & Configure a fly app 
We need to create and configure a fly app from our nestjs application. Run the command below from your nestjs app **root** directory to create, configure, and (for most apps) deploy a new fly application. In my case the root was monorepo_root/apps/api.
```
fly launch
```
This command generates a fly.toml file with default configuration that can be edited using a web interface.

> **Note: Fly expects the app to listen on port 8080 by default, so tweak the default configuration when prompted to do so and set the listening port to 8080.** 
![fly launch screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/beuw1t1ejgk6phav1lss.PNG)
> **Note: Also change the nest app to listen on the same port(8080) from main.ts/js as shown below**
![Change default port in nestjs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d5b60omfvsk3c7w6u5yb.PNG)

### Step 4: Deploying the app
To deploy the app run the command below (from the root of your nest app). 
```
fly deploy
```
This command detects our dockerfile, builds an image and deploys a container from it. If the build is successful, a url will be generated for you to access the app.

### Step 5: Setting environment variables
To set runtime environment variables, use `fly secrets set KEY=VALUE` syntax to set sensitive variables that should not be included in the built docker image. 
Example: 
![setting environment variables](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/brqgxkn2zfzoxy904zfy.PNG)
You can also import bulk values from your .env file by doing:
`fly secrets import < .env`

This then updates each Machine belonging to that Fly App with the new environment variables. This involves a restart of the Machine(s). 

Congratulations🎊