Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
node_modules
coverage
dist
.env
.DS_Store
.git
.gitignore
Dockerfile
docker-compose.yml
test
.vscode
npm-debug.log
*.md
18 changes: 14 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Use Node LTS
FROM node:20-alpine
FROM node:20-alpine AS builder

# Set working directory
WORKDIR /app
Expand All @@ -8,15 +8,25 @@ WORKDIR /app
COPY package*.json ./
RUN npm install

# Copy project
# Copy project sources and generate Prisma client
COPY . .

# Generate Prisma client
RUN npx prisma generate

# Build app
RUN npm run build

# Keep only production dependencies
RUN npm prune --production

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production

COPY package*.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/src/generated ./src/generated

# Expose port
EXPOSE 3000

Expand Down
3 changes: 3 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
"author": "",
"private": true,
"license": "UNLICENSED",
"engines": {
"node": ">=20 <21"
},
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
Expand Down
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
generator client {
provider = "prisma-client"
output = "../src/generated/client"
binaryTargets = ["native", "linux-musl"]
}

datasource db {
Expand Down
32 changes: 32 additions & 0 deletions src/dockerfile.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { readFileSync } from 'fs';
import { join } from 'path';

describe('Docker build configuration', () => {
const root = join(__dirname, '..');
const dockerfile = readFileSync(join(root, 'Dockerfile'), 'utf8');
const schema = readFileSync(join(root, 'prisma', 'schema.prisma'), 'utf8');
const packageJson = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));

it('uses node:20-alpine for both build and runtime stages', () => {
expect(dockerfile).toContain('FROM node:20-alpine AS builder');
expect(dockerfile).toContain('FROM node:20-alpine AS runner');
});

it('prunes development dependencies after build', () => {
expect(dockerfile).toMatch(/npm prune --production/);
});

it('copies built dist artifacts and generated Prisma client into the final image', () => {
expect(dockerfile).toContain('COPY --from=builder /app/dist ./dist');
expect(dockerfile).toContain('COPY --from=builder /app/src/generated ./src/generated');
});

it('restricts Prisma engine binaries for Linux musl builds', () => {
expect(schema).toContain('binaryTargets = ["native", "linux-musl"]');
});

it('declares a Node engine version constraint in package.json', () => {
expect(packageJson.engines).toBeDefined();
expect(packageJson.engines.node).toBe('>=20 <21');
});
});