How to Deploy Node.js to Docker Without Writing a Dockerfile

M
Miget Team
Writer
January 26, 2026
5 min read

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 ci instead of npm install for reproducible builds
  • Pruning devDependencies after build
  • Choosing the right base image (node:slim vs node: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:

  1. Detect Node.js from your package.json
  2. Detect npm/yarn/pnpm from your lockfile
  3. Read version from .nvmrc, .node-version, or engines.node
  4. Run npm ci (or equivalent)
  5. Execute your build script if present
  6. Prune devDependencies
  7. Output a slim production image

What Package Managers Does migetpacks Support?

migetpacks automatically detects your package manager from lockfiles:

LockfilePackage Manager
pnpm-lock.yamlpnpm
yarn.lockyarn
package-lock.jsonnpm

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:

PrioritySourceExample
1NODE_VERSION env varNODE_VERSION=20
2.node-version file22.16.0
3.nvmrc file20
4engines.node in package.json">=20"
5DefaultLatest 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?

FeaturemigetpacksPaketo
ConfigurationZero-configRequires project.toml
Image sizeSlim (node-slim base)Larger (Ubuntu-based)
Build speedFast (BuildKit)Slower
Dockerfile fallbackYesNo
Languages1410+
DHI supportYes (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

Stay UpdatedWith Latest Posts

Subscribe to our newsletter and never miss a new blog post, update, or special offer from the Miget team.