Skip to content

docker: add multi-stage Dockerfile for session-api service#5

Open
Shubham-Aswekar wants to merge 2 commits intohemanth5544:mainfrom
Shubham-Aswekar:dockerize-monorepo
Open

docker: add multi-stage Dockerfile for session-api service#5
Shubham-Aswekar wants to merge 2 commits intohemanth5544:mainfrom
Shubham-Aswekar:dockerize-monorepo

Conversation

@Shubham-Aswekar
Copy link

@Shubham-Aswekar Shubham-Aswekar commented Jan 3, 2026

What this PR does

  • Adds a multi-stage Dockerfile for the session-api service (apps/api)
  • Builds the API using npm workspaces and internal packages
  • Produces a runnable container for the API service

Notes

  • This PR only Dockerizes the API service
  • The API depends on MongoDB, which is expected to be provided externally
  • Dockerfiles for ws and web services will be added in follow-up PRs

How to run

docker build -f apps/api/Dockerfile -t session-api .
docker run -p 2000:2000 session-api


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Chores**
  * Added containerization support for the API service with optimized multi-stage build configuration, enabling efficient deployment in isolated environments with consistent runtime setup.

<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

@coderabbitai
Copy link

coderabbitai bot commented Jan 3, 2026

📝 Walkthrough

Walkthrough

A new multi-stage Dockerfile has been introduced for the API service. The builder stage installs dependencies and builds the @quick-sync/logger and @quick-sync/session-api workspaces. The runtime stage copies the built artifacts and dependencies, exposes port 2000, and runs the npm start command.

Changes

Cohort / File(s) Summary
Docker Configuration
apps/api/Dockerfile
New file: Multi-stage build pattern with node:20-alpine base image. Builder stage handles dependency installation and workspace compilation. Runtime stage includes dist, node_modules, and logger package distribution. Port 2000 exposed.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A Dockerfile hops into place,
Multi-stage build at a rapid pace!
Alpine images lean and light,
Dependencies bundled just right,
Port 2000 opens wide—our API takes flight! 🚀

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'docker: add multi-stage Dockerfile for session-api service' accurately and clearly describes the main change—introduction of a multi-stage Dockerfile for the API service.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
apps/api/Dockerfile (2)

9-9: Custom PATH modification is likely unnecessary.

The custom PATH with workspace-specific node_modules/.bin directories is unnecessary when using npm workspaces. The npm run commands automatically resolve binaries from the appropriate workspace context.

🔎 Simplification
-ENV PATH="/app/node_modules/.bin:/app/packages/logger/node_modules/.bin:/app/apps/api/node_modules/.bin:$PATH"
-
 RUN npm install

28-28: Prefer running Node.js directly over npm.

Using npm run start adds unnecessary overhead and prevents proper signal handling (SIGTERM/SIGINT). Node.js should be run directly in production containers for better performance and graceful shutdown behavior.

🔎 Run node directly

Assuming your start script runs something like node dist/index.js, replace npm with:

-CMD ["npm","run","start"]
+CMD ["node", "dist/index.js"]

If you need environment-specific configuration, you can also use:

-CMD ["npm","run","start"]
+CMD ["node", "--enable-source-maps", "dist/index.js"]

This provides better signal handling for graceful shutdown when the container stops.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6614021 and 9faa205.

📒 Files selected for processing (1)
  • apps/api/Dockerfile


ENV PATH="/app/node_modules/.bin:/app/packages/logger/node_modules/.bin:/app/apps/api/node_modules/.bin:$PATH"

RUN npm install
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use npm ci for reproducible builds.

npm install can install different dependency versions if package-lock.json is out of sync, leading to inconsistent builds. Use npm ci for reproducible, deterministic builds in CI/CD and Docker environments.

-RUN npm install
+RUN npm ci
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RUN npm install
RUN npm ci
🤖 Prompt for AI Agents
In apps/api/Dockerfile around line 11, the Dockerfile uses "RUN npm install"
which can yield non-deterministic installs; replace that command with "RUN npm
ci" to ensure reproducible, lockfile-driven installs (for production images
consider "RUN npm ci --only=production" or equivalent flags to skip dev deps).

Comment on lines +17 to +24
FROM node:20-alpine

WORKDIR /app

COPY --from=builder /app/apps/api/package.json .
COPY --from=builder /app/apps/api/dist/ /app/dist/
COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/packages/logger /app/packages/logger
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Container runs as root user.

The runtime image doesn't specify a USER directive, causing the container to run as root. This violates security best practices and increases the attack surface if the container is compromised.

🔎 Add non-root user
 FROM node:20-alpine
 
 WORKDIR /app
 
+# Create non-root user
+RUN addgroup -g 1001 -S nodejs && \
+    adduser -S nodejs -u 1001
+
 COPY --from=builder /app/apps/api/package.json .
 COPY --from=builder /app/apps/api/dist/ /app/dist/
 COPY --from=builder /app/node_modules /app/node_modules
 COPY --from=builder /app/packages/logger /app/packages/logger
 
+RUN chown -R nodejs:nodejs /app
+
+USER nodejs
+
 EXPOSE 2000
 
 CMD ["npm","run","start"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/apps/api/package.json .
COPY --from=builder /app/apps/api/dist/ /app/dist/
COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/packages/logger /app/packages/logger
FROM node:20-alpine
WORKDIR /app
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
COPY --from=builder /app/apps/api/package.json .
COPY --from=builder /app/apps/api/dist/ /app/dist/
COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/packages/logger /app/packages/logger
RUN chown -R nodejs:nodejs /app
USER nodejs
EXPOSE 2000
CMD ["npm","run","start"]
🤖 Prompt for AI Agents
In apps/api/Dockerfile around lines 17-24 the container never switches from root
to a non-root user; create a non-root user and switch to it, ensure
files/directories under /app are owned by that user and writable where needed,
and set the USER at the end of the Dockerfile. Specifically: add steps to create
a user/group (or use the existing node user in the base image), chown /app and
any runtime-writeable dirs to that UID/GID, avoid binding to privileged ports,
and add a USER directive so the container does not run as root at runtime.

Comment on lines +21 to +24
COPY --from=builder /app/apps/api/package.json .
COPY --from=builder /app/apps/api/dist/ /app/dist/
COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/packages/logger /app/packages/logger
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check API dependencies and workspace configuration

echo "=== API package.json dependencies ==="
cat apps/api/package.json | jq '.dependencies, .devDependencies' 2>/dev/null || cat apps/api/package.json

echo -e "\n=== Logger package name ==="
cat packages/logger/package.json | jq '.name' 2>/dev/null || cat packages/logger/package.json

echo -e "\n=== Root package.json workspaces ==="
cat package.json | jq '.workspaces' 2>/dev/null || cat package.json

echo -e "\n=== Dockerfile content (apps/api/Dockerfile) ==="
cat apps/api/Dockerfile

Repository: hemanth5544/quicksync

Length of output: 1250


🏁 Script executed:

#!/bin/bash
# Check if logger package is meant to be published or workspace-only

echo "=== Logger package.json (complete) ==="
cat packages/logger/package.json

echo -e "\n=== Checking for .npmrc or registry config ==="
cat .npmrc 2>/dev/null || echo "No .npmrc file"

echo -e "\n=== Checking for npm publish scripts in root package.json ==="
cat package.json | jq '.scripts | keys[] | select(contains("publish"))'

echo -e "\n=== Checking root package.json private field ==="
cat package.json | jq '.private'

Repository: hemanth5544/quicksync

Length of output: 828


Change API's dependency on @quick-sync/logger to use workspace protocol.

The API references @quick-sync/logger with version "*", which causes npm to attempt resolution from the npm registry. Since the logger package is marked as "private": true and is not published, this reference will fail to resolve at runtime. During the build stage in the monorepo context, this resolves correctly, but the flattened runtime structure copies node_modules without a proper mechanism to resolve the workspace dependency.

Change the dependency in apps/api/package.json to use the workspace protocol:

"@quick-sync/logger": "workspace:*"

This ensures the dependency resolves correctly within the monorepo structure during both build and runtime.

🤖 Prompt for AI Agents
In apps/api/Dockerfile around lines 21 to 24, the runtime image copies
node_modules and a private workspace package but the API's package.json
currently depends on @quick-sync/logger as "*" which causes npm to try the
registry and fail; update apps/api/package.json to set the logger dependency to
the workspace protocol ("@quick-sync/logger": "workspace:*"), then rebuild the
image so the workspace dependency is resolved locally and included correctly in
the runtime build.


COPY --from=builder /app/apps/api/package.json .
COPY --from=builder /app/apps/api/dist/ /app/dist/
COPY --from=builder /app/node_modules /app/node_modules
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Production image includes development dependencies.

Copying the entire node_modules directory from the builder includes all development dependencies (testing frameworks, build tools, etc.), significantly increasing image size and exposing unnecessary packages that could contain security vulnerabilities.

🔎 Install production dependencies only

Instead of copying node_modules from builder, install production dependencies in the runtime stage:

 FROM node:20-alpine
 
 WORKDIR /app
 
 COPY --from=builder /app/apps/api/package.json .
 COPY --from=builder /app/apps/api/dist/ /app/dist/
-COPY --from=builder /app/node_modules /app/node_modules
 COPY --from=builder /app/packages/logger /app/packages/logger
+
+# Copy only root package files needed for workspace resolution
+COPY --from=builder /app/package*.json ./
+
+# Install production dependencies only
+RUN npm ci --only=production --workspace=@quick-sync/session-api
 
 EXPOSE 2000

Note: This assumes workspace dependencies are properly configured. You may need to adjust the approach based on your workspace setup.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/api/Dockerfile around line 23, the Dockerfile copies the entire
node_modules from the builder which brings dev dependencies into the production
image; instead, remove the COPY --from=builder /app/node_modules step and in the
final/runtime stage copy only package.json and package-lock.json (or appropriate
lockfiles) from the builder and run a production-only install (e.g. npm ci
--omit=dev or npm ci --production depending on your npm version) so only
production dependencies are installed into the runtime image.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant