How to Deploy Node.js to Docker Without Writing a Dockerfile
You can containerize any Node.js application without writing a Dockerfile using migetpacks. It auto-detects your package manager (npm, yarn, or pnpm), reads your Node version from .nvmrc or package.json, runs your build script, prunes dev dependencies, and produces an optimized production image. Three commands, zero configuration.
Why Is Writing a Dockerfile for Node.js So Complicated?
A production-ready Node.js Dockerfile requires:
- Multi-stage builds to separate build and runtime
- Correct layer ordering for dependency caching
npm ciinstead ofnpm installfor reproducible builds- Pruning devDependencies after build
- Choosing the right base image (
node:slimvsnode:alpine) - Setting
NODE_ENV=production - Non-root user for security
Most tutorials get this wrong. You end up with bloated images, slow builds, or security issues.
How Do I Containerize a Node.js App Without a Dockerfile?
Open your terminal, navigate to your project directory, and run:
cd ~/projects/my-node-app
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-node-app:latest \
miget/migetpacks:latest
That's it. migetpacks will:
- Detect Node.js from your
package.json - Detect npm/yarn/pnpm from your lockfile
- Read version from
.nvmrc,.node-version, orengines.node - Run
npm ci(or equivalent) - Execute your
buildscript if present - Prune devDependencies
- Output a slim production image
What Package Managers Does migetpacks Support?
migetpacks automatically detects your package manager from lockfiles:
| Lockfile | Package Manager |
|---|---|
pnpm-lock.yaml | pnpm |
yarn.lock | yarn |
package-lock.json | npm |
No configuration needed. If multiple lockfiles exist, migetpacks warns you and uses the highest-priority one.
How Does migetpacks Detect My Node.js Version?
Version is resolved in this order:
| Priority | Source | Example |
|---|---|---|
| 1 | NODE_VERSION env var | NODE_VERSION=20 |
| 2 | .node-version file | 22.16.0 |
| 3 | .nvmrc file | 20 |
| 4 | engines.node in package.json | ">=20" |
| 5 | Default | Latest LTS |
Version constraints like >=20, 20.x, or ^20.0.0 are normalized automatically for Docker compatibility.
What Does the Generated Dockerfile Look Like?
migetpacks generates an optimized multi-stage Dockerfile internally:
# Builder stage
FROM node:22 AS builder
WORKDIR /build
COPY package.json package-lock.json ./
ENV NODE_ENV=production
RUN npm ci
COPY . .
RUN npm run build && npm prune --production
# Runtime stage
FROM node:22-slim
WORKDIR /app
COPY --from=builder /build /app
ENV NODE_ENV=production
CMD ["node", "index.js"]
You never write or maintain this file - migetpacks handles it automatically.
How Do I Build a Next.js App with migetpacks?
The same command works for Next.js, Vite, Express, or any Node.js framework. Just navigate to your project:
cd ~/projects/my-nextjs-app
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-nextjs:latest \
miget/migetpacks:latest
For build-time environment variables (like NEXT_PUBLIC_* or VITE_*), pass them directly:
cd ~/projects/my-vite-app
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-vite:latest \
-e VITE_API_URL="https://api.example.com" \
miget/migetpacks:latest
How Do I Use migetpacks in GitHub Actions?
Add this step to your workflow file (.github/workflows/build.yml):
- name: Build with migetpacks
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace/source:ro \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /home/runner/.docker/config.json:/root/.docker/config.json:ro \
-e OUTPUT_IMAGE=ghcr.io/${{ github.repository }}:${{ github.sha }} \
-e CACHE_IMAGE=ghcr.io/${{ github.repository }}:cache \
miget/migetpacks:latest
The CACHE_IMAGE enables cross-build caching for faster CI runs. See the full GitHub Actions guide.
How Do I Increase Memory for Large Builds?
For large Next.js or Vite builds that run out of memory, pass NODE_OPTIONS:
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-app:latest \
-e NODE_OPTIONS="--max-old-space-size=4096" \
miget/migetpacks:latest
Any environment variable not recognized by migetpacks is automatically injected into the build.
What's the Difference Between migetpacks and Paketo Buildpacks?
| Feature | migetpacks | Paketo |
|---|---|---|
| Configuration | Zero-config | Requires project.toml |
| Image size | Slim (node-slim base) | Larger (Ubuntu-based) |
| Build speed | Fast (BuildKit) | Slower |
| Dockerfile fallback | Yes | No |
| Languages | 14 | 10+ |
| DHI support | Yes (distroless) | No |
How Do I Build Secure Distroless Images?
Enable Docker Hardened Images for minimal, CVE-free containers:
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-app:latest \
-e USE_DHI=true \
miget/migetpacks:latest
DHI images are distroless - no shell, no package manager, minimal attack surface.
Next Steps
- Full Node.js documentation - version detection, caching, run commands
- Deploy on Miget - unlimited apps, one price
- Star on GitHub - migetpacks is open source