Skip to main content
RapidDev - Software Development Agency
cursor-tutorial

How to get simpler Dockerfiles from Cursor

Cursor generates bloated Dockerfiles with unnecessary layers, missing multi-stage builds, and root user execution. By adding Docker rules to .cursorrules and referencing your package.json when prompting, you get production-ready Dockerfiles with multi-stage builds, proper caching, non-root users, and minimal image sizes under 200MB.

What you'll learn

  • How to configure .cursorrules for Docker best practices
  • How to prompt Cursor for multi-stage Docker builds
  • How to optimize layer caching in Cursor-generated Dockerfiles
  • How to verify Cursor Dockerfiles follow security best practices
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate6 min read10-15 minCursor Free+, Node.js projects with DockerMarch 2026RapidDev Engineering Team
TL;DR

Cursor generates bloated Dockerfiles with unnecessary layers, missing multi-stage builds, and root user execution. By adding Docker rules to .cursorrules and referencing your package.json when prompting, you get production-ready Dockerfiles with multi-stage builds, proper caching, non-root users, and minimal image sizes under 200MB.

Getting simpler Dockerfiles from Cursor

Cursor often generates single-stage Dockerfiles that copy everything, install dev dependencies in production, and run as root. This tutorial shows how to get minimal, secure, multi-stage Dockerfiles that follow production best practices.

Prerequisites

  • Cursor installed with a Node.js project
  • Docker installed locally
  • A package.json with defined scripts
  • Familiarity with Cursor Chat (Cmd+L)

Step-by-step guide

1

Add Docker rules to .cursor/rules

Create rules that enforce Docker best practices. These prevent Cursor from generating insecure or bloated Dockerfiles.

.cursor/rules/docker.mdc
1---
2description: Dockerfile generation rules
3globs: "Dockerfile*,docker-compose*.yml"
4alwaysApply: true
5---
6
7## Dockerfile Rules
8- ALWAYS use multi-stage builds (builder + production stages)
9- Use node:22-alpine as base, NOT node:22 (saves 700MB+)
10- Copy package.json and package-lock.json BEFORE source code (layer caching)
11- Run 'npm ci --omit=dev' in production stage (no devDependencies)
12- ALWAYS add a non-root USER (node user exists in official images)
13- Use COPY --from=builder for production artifacts only
14- Set NODE_ENV=production
15- Use HEALTHCHECK instruction
16- NEVER use 'npm install' use 'npm ci' for reproducible builds
17- Expose the correct port from package.json scripts

Expected result: Cursor generates optimized Dockerfiles following production best practices.

2

Generate a multi-stage Dockerfile

Ask Cursor to create a Dockerfile referencing your package.json so it knows the correct build commands, entry point, and port.

Dockerfile
1// Cursor Chat prompt (Cmd+L):
2// @package.json Generate a production Dockerfile for this
3// Node.js app. Use multi-stage build with node:22-alpine.
4// Stage 1: install all deps and build.
5// Stage 2: production-only deps and compiled output.
6// Use non-root user, proper layer caching, and HEALTHCHECK.
7
8# Stage 1: Build
9FROM node:22-alpine AS builder
10WORKDIR /app
11COPY package.json package-lock.json ./
12RUN npm ci
13COPY . .
14RUN npm run build
15
16# Stage 2: Production
17FROM node:22-alpine
18WORKDIR /app
19ENV NODE_ENV=production
20COPY package.json package-lock.json ./
21RUN npm ci --omit=dev && npm cache clean --force
22COPY --from=builder /app/dist ./dist
23USER node
24EXPOSE 3000
25HEALTHCHECK --interval=30s CMD wget -q --spider http://localhost:3000/health || exit 1
26CMD ["node", "dist/index.js"]

Pro tip: Copying package.json before source code means Docker caches the npm ci layer. Source code changes do not trigger a full dependency reinstall.

Expected result: A multi-stage Dockerfile under 20 lines with optimized layer caching and security.

3

Generate a matching .dockerignore

Ask Cursor to create a .dockerignore that prevents unnecessary files from entering the build context. This reduces build time and prevents secrets from leaking into images.

.dockerignore
1// Cursor Chat prompt (Cmd+L):
2// Generate a .dockerignore for this Node.js project.
3// Exclude node_modules, .git, test files, docs, IDE
4// configs, and environment files.
5
6node_modules
7.git
8.gitignore
9*.md
10!README.md
11tests/
12__tests__/
13coverage/
14.env*
15.cursor/
16.vscode/
17dist/
18*.log

Expected result: A .dockerignore that keeps the build context minimal and secure.

4

Generate a docker-compose for local development

Ask Cursor to create a docker-compose.yml for local development that mounts source code, enables hot reload, and includes common services like PostgreSQL and Redis.

Cursor Chat prompt
1// Cursor Chat prompt (Cmd+L):
2// @package.json @Dockerfile Generate a docker-compose.yml
3// for local development with:
4// - App service with volume mount for hot reload
5// - PostgreSQL 16 with persistent volume
6// - Redis for caching
7// - Proper depends_on with healthchecks

Expected result: A docker-compose.yml with the app, database, and cache services configured for local development.

5

Verify the image size and security

Build the Docker image and verify it meets size and security targets. Use Cursor's terminal to run the build and inspection commands.

Terminal
1# Build and check size:
2docker build -t myapp:latest .
3docker images myapp:latest
4# Target: under 200MB for a Node.js app
5
6# Check for root user (should show 'node'):
7docker run --rm myapp:latest whoami
8
9# Check for no dev dependencies:
10docker run --rm myapp:latest npm ls --omit=dev

Expected result: Image under 200MB, running as non-root user, with no dev dependencies installed.

Complete working example

Dockerfile
1# Stage 1: Install dependencies and build
2FROM node:22-alpine AS builder
3WORKDIR /app
4
5# Copy dependency files first for layer caching
6COPY package.json package-lock.json ./
7RUN npm ci
8
9# Copy source and build
10COPY tsconfig.json ./
11COPY src/ ./src/
12RUN npm run build
13
14# Stage 2: Production image
15FROM node:22-alpine
16WORKDIR /app
17
18ENV NODE_ENV=production
19
20# Install production dependencies only
21COPY package.json package-lock.json ./
22RUN npm ci --omit=dev \
23 && npm cache clean --force \
24 && rm -rf /tmp/*
25
26# Copy built artifacts from builder
27COPY --from=builder /app/dist ./dist
28
29# Security: run as non-root user
30USER node
31
32# Expose application port
33EXPOSE 3000
34
35# Health check for orchestrators
36HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
37 CMD wget -q --spider http://localhost:3000/health || exit 1
38
39# Start the application
40CMD ["node", "dist/index.js"]

Common mistakes when getting simpler Dockerfiles from Cursor

Why it's a problem: Using node:22 instead of node:22-alpine

How to avoid: Add 'Use node:22-alpine as base' to .cursorrules. Cursor will default to Alpine.

Why it's a problem: Single-stage build that includes dev dependencies

How to avoid: Always request multi-stage builds in your prompt and add the rule to .cursorrules.

Why it's a problem: Running as root user in the container

How to avoid: Add 'ALWAYS add USER node instruction' to your Docker rules. The node user exists by default in official Node.js images.

Best practices

  • Always use multi-stage builds to separate build and production stages
  • Use Alpine-based images to reduce image size by 80%+
  • Copy package.json before source code for optimal layer caching
  • Use npm ci instead of npm install for reproducible builds
  • Run containers as non-root user (USER node)
  • Add HEALTHCHECK for container orchestrator integration
  • Generate .dockerignore to keep build context minimal

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Create a production Dockerfile for a Node.js TypeScript app. Use multi-stage build with node:22-alpine. Stage 1: install all deps and build TypeScript. Stage 2: production deps only, copy built artifacts, non-root user, HEALTHCHECK. Also create a .dockerignore and a docker-compose.yml for local dev with PostgreSQL and Redis.

Cursor Prompt

In Cursor Chat (Cmd+L): @package.json @tsconfig.json Generate a production-ready Dockerfile. Use multi-stage build with node:22-alpine. Optimize layer caching (copy package files first). Production stage: npm ci --omit=dev, USER node, HEALTHCHECK. Target image under 200MB.

Frequently asked questions

Why does Cursor generate such large Dockerfiles?

Cursor's training data includes many tutorial-level Dockerfiles that prioritize simplicity over optimization. Adding Docker-specific rules and requesting multi-stage builds produces much smaller images.

Should I use distroless instead of Alpine?

Distroless images are even smaller and more secure but lack a shell for debugging. Use Alpine for most projects and distroless for high-security production containers. Specify your preference in the prompt.

Can Cursor generate Dockerfiles for monorepos?

Yes. Reference the specific package's package.json and specify the build context. Cursor can generate Dockerfiles that build only the needed package from a monorepo.

How do I handle environment variables in Docker?

Use ARG for build-time variables and ENV for runtime. Never bake secrets into the image. Ask Cursor to use environment variables for all configuration.

Can Cursor Agent run Docker commands?

Yes, in Agent mode with terminal access enabled. However, for Docker builds that take minutes, it is better to run them manually or through CI/CD.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.