nodejs-containers

v2026.09.24

Node.js container optimization — Alpine, multi-stage builds, node_modules caching, BuildKit mounts (900MB to ~100MB). Use when working with Node.js containers or optimizing image sizes.

GitHub
安装命令
npx skhub add laurigates/nodejs-containers
Markdown
SKILL.md

Node.js Container Optimization

Expert knowledge for building optimized Node.js container images using Alpine variants, multi-stage builds, and Node.js-specific dependency management patterns.

When to Use This Skill

Use this skill when...Use container-development instead when...
Building Node.js-specific DockerfilesGeneral multi-stage build patterns
Optimizing Node.js image sizesLanguage-agnostic container security
Handling npm/yarn/pnpm in containersDocker Compose configuration
Dealing with native module buildsNon-Node.js container optimization

Core Expertise

Node.js Container Challenges:

  • Large node_modules directories (100-500MB)
  • Full base images include build tools (~900MB)
  • Separate dev and production dependencies
  • Different package managers (npm, yarn, pnpm)
  • Native modules requiring build tools

Key Capabilities:

  • Alpine-based images (~100MB vs ~900MB full)
  • Multi-stage builds separating build and runtime
  • BuildKit cache mounts for node_modules
  • Production-only dependency installation
  • Non-root user configuration

Optimized Multi-Stage Pattern (Node Servers)

The recommended pattern achieves ~100-150MB images:

# Dependencies stage - production only
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# Build stage - includes devDependencies
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Runtime stage - minimal
FROM node:20-alpine
WORKDIR /app

# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
    adduser -u 1001 -S nodejs -G nodejs

# Copy dependencies and built app
COPY --from=deps --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=build --chown=nodejs:nodejs /app/dist ./dist
COPY --chown=nodejs:nodejs package.json ./

USER nodejs
EXPOSE 3000

HEALTHCHECK --interval=30s CMD node healthcheck.js || exit 1

CMD ["node", "dist/server.js"]

BuildKit Cache Mounts (Fastest Builds)

# syntax=docker/dockerfile:1

FROM node:20-alpine AS build
WORKDIR /app

# Cache mount for npm cache
RUN --mount=type=cache,target=/root/.npm \
    --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=package-lock.json,target=package-lock.json \
    npm ci

COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]

Build performance:

  • First build: ~2-3 minutes
  • Subsequent builds (no package changes): ~10-20 seconds
  • Subsequent builds (package changes): ~30-60 seconds

Package Manager Patterns

npm

COPY package*.json ./
RUN npm ci --only=production
RUN npm cache clean --force

yarn

COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile --production
RUN yarn cache clean

pnpm

RUN npm install -g pnpm
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod
# pnpm creates smaller node_modules with hard links (20-30% smaller)

Next.js on Bun: build with Bun, run with Node

Bun works for the dependency and build stages of a Next.js image, but the runtime stage that serves .next/standalone must be Node.js. The standalone output targets Node, and Bun does not resolve the React Server Components SSR modules it loads (react-dom/server.edge, react-dom/server-rendering-stub, react-server-dom-webpack/client.edge), so it fails at runtime with "Could not resolve" errors.

FROM oven/bun:1-debian AS deps        # install
FROM oven/bun:1-debian AS builder     # next build
FROM gcr.io/distroless/nodejs22-debian12 AS runner
CMD ["server.js"]

Distroless runtime: no shell, so no child_process to CLI tools

A distroless Node image contains Node and nothing else: no /bin/sh, gzip, pg_dump, or psql. Application code that shells out through node:child_process (exec, execSync, spawn of a CLI) works in local dev and fails only in production, with spawn /bin/sh ENOENT. Use Node built-ins or a library instead:

Shell toolIn-process replacement
gzip / gunzipnode:zlib (gzipSync, createGzip, gunzipSync)
cat, cp, file writesnode:fs
pg_dump / psqlexport/import through the app's database client or ORM

The same constraint means ops scripts cannot be kubectl exec'd into the running app pod. Ship them in a separate image and run them as a Job. To stop the mistake before review, ban the import with a lint rule (for example Biome noRestrictedImports on node:child_process for server source).

Performance Impact

MetricFull Node (900MB)Alpine (350MB)Multi-Stage (100MB)Improvement
Image Size900MB350MB100MB89% reduction
Pull Time3m 20s1m 10s25s87% faster
Build Time4m 30s3m 15s2m 30s44% faster
Rebuild (cached)2m 10s1m 30s15s88% faster
Memory Usage512MB256MB180MB65% reduction

Security Impact

Image TypeVulnerabilitiesSizeRisk
node:20 (Debian)45-60 CVEs900MBHigh
node:20-alpine8-12 CVEs350MBMedium
Multi-stage Alpine4-8 CVEs100MBLow
Distroless Node2-4 CVEs120MBVery Low

Agentic Optimizations

ContextCommandPurpose
Fast rebuildDOCKER_BUILDKIT=1 docker build --target build .Build only build stage
Size checkdocker images app --format "table {{.Repository}}\t{{.Size}}"Compare sizes
Layer analysisdocker history app:latest --human --no-trunc | head -20Find large layers
Dependency auditdocker run --rm app npm audit --productionCheck vulnerabilities
Cache cleardocker builder prune --filter type=exec.cachemountClear BuildKit cache
Test locallydocker run --rm -p 3000:3000 appQuick local test

Best Practices

  • Use Alpine variants for smaller images
  • Use npm ci not npm install (reproducible builds)
  • Separate dev and production dependencies
  • Run as non-root user
  • Use multi-stage builds for production
  • Layer package.json separately from source code
  • Add .dockerignore to exclude node_modules, tests

For detailed examples, advanced patterns, and best practices, see REFERENCE.md.

Related Skills

  • container-development - General container patterns, multi-stage builds, security
  • go-containers - Go-specific container optimizations
  • python-containers - Python-specific container optimizations
发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

Sep 24, 2026

分类

未分类

许可证

MIT

源路径

container-plugin/skills/nodejs-containers

默认分支

main

最新提交

1668324

Tree SHA

b2d4cc3