I'm attempting to configure a two-component (frontend + backend) monorepo deployment using Digital Ocean's App Platform. I'm starting with the backend. The monorepo looks like:
client/ <-- NextJS project
server/ <-- NestJS project
The Dockerfile (server/Dockerfile) is simple:
FROM node:24-alpine
COPY . .
RUN npm install && npm run build && npm prune --production
CMD ["npm", "run", "start:prod"]
And the service portion of Digital Ocean app spec looks like:
services:
- dockerfile_path: server/Dockerfile
gitlab:
branch: main
deploy_on_push: true
repo: craigotis/myproject
http_port: 8080
instance_count: 1
instance_size_slug: apps-s-1vcpu-0.5gb
internal_ports:
- 4000
name: myproject-server
source_dir: server
The deployment logs start out fine:
Nov 01 17:40:00 ╭──────────── git repo clone ───────────╼
Nov 01 17:40:00 › fetching app source code
Nov 01 17:40:00 => Selecting branch "main"
Nov 01 17:40:21 => Checking out commit "...."
Nov 01 17:40:25
Nov 01 17:40:25 ✔ cloned repo to /.app_platform_workspace
Nov 01 17:40:25 ╰────────────────────────────────────────╼
Nov 01 17:40:25
Nov 01 17:40:25 › applying source directory server
Nov 01 17:40:25 ✔ using workspace root /.app_platform_workspace/server
Nov 01 17:40:25
Nov 01 17:40:25 ╭──────────── dockerfile build ───────────╼
Nov 01 17:40:25 › using dockerfile /.app_platform_workspace/server/Dockerfile
Nov 01 17:40:25 › using build context /.app_platform_workspace/server
Nov 01 17:40:25
Nov 01 17:40:25 INFO[0000] Retrieving image manifest node:24-alpine
Nov 01 17:40:25 INFO[0000] Retrieving image library/node:24-alpine from registry mirror <registry-uri-0>
Nov 01 17:40:25 INFO[0000] Retrieving image manifest node:24-alpine
Nov 01 17:40:25 INFO[0000] Returning cached image manifest
Nov 01 17:40:25 INFO[0000] Built cross stage deps: map[]
Nov 01 17:40:25 INFO[0000] Retrieving image manifest node:24-alpine
Nov 01 17:40:25 INFO[0000] Returning cached image manifest
Nov 01 17:40:25 INFO[0000] Retrieving image manifest node:24-alpine
Nov 01 17:40:25 INFO[0000] Returning cached image manifest
Nov 01 17:40:25 INFO[0000] Executing 0 build triggers
Nov 01 17:40:25 INFO[0000] Building stage 'node:24-alpine' [idx: '0', base-idx: '-1']
Nov 01 17:40:25 INFO[0000] Checking for cached layer <registry-uri-1>
Nov 01 17:40:25 INFO[0000] No cached layer found for cmd RUN npm install && npm run build && npm prune --production
Nov 01 17:40:25 INFO[0000] Unpacking rootfs as cmd COPY . . requires it.
Nov 01 17:40:28 INFO[0002] Initializing snapshotter ...
Nov 01 17:40:28 INFO[0002] Taking snapshot of full filesystem...
Nov 01 17:40:32 INFO[0007] COPY . .
Nov 01 17:40:32 INFO[0007] Taking snapshot of files...
Nov 01 17:40:32 INFO[0007] RUN npm install && npm run build && npm prune --production
Nov 01 17:40:33 INFO[0007] Cmd: /bin/sh
Nov 01 17:40:33 INFO[0007] Args: [-c npm install && npm run build && npm prune --production]
Nov 01 17:40:33 INFO[0007] Running: [/bin/sh -c npm install && npm run build && npm prune --production]
But the build process fails because it seems the COPY . . command pulled in the entire contents of the repo - not just the subdirectory. As a result, there are failures like:
Nov 01 17:41:05 proc/1/cwd/client/app/page.tsx:32:9 - error TS17004: Cannot use JSX unless the '--jsx' flag is provided.
Nov 01 17:41:05
Nov 01 17:41:05 32 <AnalyticsPortal state={state} />
Nov 01 17:41:05 ~~~~~~~~~~~~~~~~~~~~~~~~~
Note that client and server both have been pulled into the Dockerfile. Is there a way to deploy individual components using the Dockerfile strategy from a monorepo on Digital Ocean?
--context-sub-pathmight be the trick, but it doesn't seem to be exposed via Digital Ocean's solution.