# Deploying a pnpm monorepo

**URL:** <https://community.fly.io/t/deploying-a-pnpm-monorepo/15167>\
**Category:** JavaScript\
**Tags:** nodejs, login-only\
**Created:** [September 2, 2023, 11:04am UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167 "2023-09-02T11:04:42Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![v2rtl](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/v2rtl/32/14900_2.png) [@v2rtl](https://community.fly.io/u/v2rtl)\
**Post date:** [September 2, 2023, 11:04am UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/1 "2023-09-02T11:04:42Z")

</div>

Hello, I’m new to Fly and I don’t understand how I should set up a pnpm monorepo on Fly, because when I follow the official article, it ends up copying all node\_modules and it inflates the image size greatly.

There is an [official guide from pnpm](https://pnpm.io/docker) but I’m a complete noob at Docker so I’m not really sure how the final Dockerfile should look.

My `fly.toml` file is:

```toml
app = "stauro"
primary_region = "arn"

[env]
PORT = "3000"

[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = true
auto_start_machines = true

```

and `Dockerfile`:

```auto
# syntax = docker/dockerfile:1

# Adjust NODE_VERSION as desired
ARG NODE_VERSION=20.5.1
FROM node:${NODE_VERSION}-slim as base

LABEL fly_launch_runtime="NodeJS"

RUN corepack enable

# Set production environment
ENV NODE_ENV=production

ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile

# Throw-away build stage to reduce size of final image
FROM base as build

# Install packages needed to build node modules
RUN apt-get update -qq && \
    apt-get install -y pkg-config build-essential 

COPY --link . .

# Install node modules
RUN pnpm i

# Final stage for app image
FROM base

# Copy built application
COPY --from=build /app/ /app

WORKDIR /app/packages/api

# Start the server by default, this can be overwritten at runtime
CMD ["pnpm", "run", "start"]

```

I have the following monorepo structure:

```auto
├── Dockerfile
├── fly.toml
├── package.json
├── packages
│ ├── api
│ ├── prisma
│ └── www
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── tsconfig.json

```

My workspace settings are these:

```auto
packages:
  - 'packages/*'

```

Could I get some guidance please how to properly write a docker file so it deploys a package under `app` successfully? (It also depends on `prisma`, so it should be built as well)

---

<div class="post-metadata">

**Author:** ![redjonzaci](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/redjonzaci/32/14794_2.png) [@redjonzaci](https://community.fly.io/u/redjonzaci)\
**Post date:** [September 2, 2023, 11:17am UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/2 "2023-09-02T11:17:33Z")

</div>

I will try my best to assist you in at most 30 mins until a Fly employee can get to this.

---

<div class="post-metadata">

**Author:** ![redjonzaci](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/redjonzaci/32/14794_2.png) [@redjonzaci](https://community.fly.io/u/redjonzaci)\
**Post date:** [September 2, 2023, 11:49am UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/3 "2023-09-02T11:49:14Z")

</div>

On it now

---

<div class="post-metadata">

**Author:** ![redjonzaci](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/redjonzaci/32/14794_2.png) [@redjonzaci](https://community.fly.io/u/redjonzaci)\
**Post date:** [September 2, 2023, 12:08pm UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/4 "2023-09-02T12:08:23Z")

</div>

When you say you followed the official article, is it a [Fly.io](http://Fly.io) article?  
Can you share the article you are referring to?

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [September 2, 2023, 2:59pm UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/5 "2023-09-02T14:59:42Z")

</div>

The official guide describes how to build and run what appears to be two independent apps that may share some common dependencies. I suspect that this doesn’t match your setup.

What would be most helpful to know is how you run your application today. As an example, it may be that your `www` and `prisma` apps are merely built, and the only app you are running is an api server that makes use of the database through prisma and serves bundled javascript based on the code in www.

Other configurations are possible. For example you may start two servers, where the www server talks to your api server.

Without knowing more, it is difficult to craft a dockerfile that does what you know. After all “monorepository” simply means many projects in one repository.

It would be helpful to see your `package.json`, both at the top level and probably also the package.json files in each directory where you start a server (I suspect that at a minimum that would include api).

---

<div class="post-metadata">

**Author:** ![v2rtl](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/v2rtl/32/14900_2.png) [@v2rtl](https://community.fly.io/u/v2rtl)\
**Post date:** [September 2, 2023, 5:31pm UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/6 "2023-09-02T17:31:34Z")

</div>

I meant this [tutorial](https://fly.io/docs/reference/monorepo/#paths)

---

<div class="post-metadata">

**Author:** ![v2rtl](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/v2rtl/32/14900_2.png) [@v2rtl](https://community.fly.io/u/v2rtl)\
**Post date:** [September 2, 2023, 5:37pm UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/7 "2023-09-02T17:37:06Z")

</div>

apologies for the lack of info, here are package json files for api and prisma:

```json
// packages/api
{
  "name": "@monorepo/api",
  "private": true,
  "type": "module",
  "version": "1.0.0",
  "exports": "./dist/schema.js",
  "types": "./dist/schema.d.ts",
  "dependencies": {},
  "devDependencies": {},
  "scripts": {
    "generate": "tsc",
    "dev": "doppler run -- tsx watch src/server.ts",
    "start": "doppler run -- node ./dist/server.js",
    "postinstall": "pnpm generate"
  }
}

// packages/prisma

{
  "name": "@monorepo/prisma",
  "private": true,
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "files": [
    "dist"
  ],
  "devDependencies": {
    "prisma": "5.0.0"
  },
  "dependencies": {
    "@pothos/plugin-prisma": "^3.52.0",
    "@prisma/client": "5.0.0"
  },
  "scripts": {
    "generate": "prisma generate",
    "postinstall": "pnpm generate"
  }
}

```

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [September 2, 2023, 6:13pm UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/8 "2023-09-02T18:13:06Z")

</div>

Since prisma doesn’t have a `start` script, it clearly isn’t an application.

I’m troubled by the fact that I don’t see any scripts being run in the build stage. I presume that you need to run something that calls the generate script in the prisma directory.

* * *

So far, I’ve only seen one start script (I’m still curious what is in web), but if you only have one application with a start script, try changing:

> [@v2rtl](#):
>
> ```dockerfile
> # Copy built application
> COPY --from=build /app/ /app
> 
> WORKDIR /app/packages/api
> 
> ```

To

```dockerfile
# Copy built application
COPY --from=build /app/packages/api /app

WORKDIR /app

```

With this change, the only app that will be in your image will be the api app. Hopefully the build process places bundled javascript from the web app and generated database access code from the prisma app into the api app; but I’m making a lot of assumptions here as I can’t see your application.

---

<div class="post-metadata">

**Author:** ![v2rtl](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/v2rtl/32/14900_2.png) [@v2rtl](https://community.fly.io/u/v2rtl)\
**Post date:** [September 4, 2023, 2:37pm UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/9 "2023-09-04T14:37:25Z")

</div>

`pnpm generate` in prisma builds a prisma client, so it’s the same as `build`

the `api` package is missing `build`, my bad, the `generate` script should be called `build`.

`www` is unrelated, I’m not intending to deploy it. I only need to deploy `api`, with a dependency on `prisma`

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [September 4, 2023, 3:04pm UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/10 "2023-09-04T15:04:51Z")

</div>

So are you good to go? Or do you have more questions?

Meanwhile, some things I can do:

- Add a js specific monorepo page to the documentation, with more JS specific advice.
- Add a `--target` option to dockerfile-node so that you can regenerate your dockerfile with only a specific target.

---

<div class="post-metadata">

**Author:** ![v2rtl](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/v2rtl/32/14900_2.png) [@v2rtl](https://community.fly.io/u/v2rtl)\
**Post date:** [September 9, 2023, 11:37am UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/11 "2023-09-09T11:37:03Z")

</div>

in the end we came up with the following Dockerfile:

```auto
FROM node:18-alpine as base

LABEL fly_launch_runtime="NodeJS"

RUN corepack enable

ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
ENV NODE_ENV=production

RUN wget -q -t3 'https://packages.doppler.com/public/cli/rsa.8004D9FF50437357.key' -O /etc/apk/keys/cli@doppler-8004D9FF50437357.rsa.pub && \
    echo 'https://packages.doppler.com/public/cli/alpine/any-version/main' | tee -a /etc/apk/repositories && \
    apk add doppler

WORKDIR /app

COPY . /app/

RUN npm pkg delete scripts.prepare

RUN rm -rf /app/packages/www

RUN pnpm i --prod && pnpm i -r --prod

WORKDIR /app/packages/prisma

RUN pnpm generate

WORKDIR /app/packages/api
EXPOSE 3000
CMD ["pnpm", "start"]

```

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/fly1/original/3X/6/e/6e8955d00cb218e186ebbe3a6ab06fefdce15290.svg) [@system](https://community.fly.io/u/system)\
**Post date:** [September 16, 2023, 11:37am UTC](https://community.fly.io/t/deploying-a-pnpm-monorepo/15167/12 "2023-09-16T11:37:58Z")

</div>

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.
