---
title: "Ultimate Next.js Standalone Dockerfile Guide (Tiny Images)"
slug: "nextjs-standalone-dockerfile-guide"
published: "2026-03-02"
updated: "2026-04-06"
categories:
  - "Docker"
tags:
  - "Next.js standalone Dockerfile"
  - "output: \"standalone\""
  - "Next.js Dockerfile"
  - "shrink Docker image size"
  - "sharp missing error"
  - "node_modules trimming"
  - "image optimization Next.js"
  - "production Next.js Dockerfile"
  - "self-hosting Next.js"
  - "Docker multi-stage build"
  - "Alpine Node image"
llm-intent: "reference"
audience-level: "intermediate"
framework-versions:
  - "next@16"
  - "node@20"
  - "docker:latest"
status: "stable"
llm-purpose: "Next.js standalone Dockerfile: reduce image size by tracing imports, copy only needed files, fix sharp errors, and build minimal production Docker images…"
llm-prereqs:
  - "Access to Next.js 16"
  - "Access to Node.js 20"
  - "Access to Docker"
  - "Access to Alpine Linux"
  - "Access to npm"
llm-outputs:
  - "Completed outcome: Next.js standalone Dockerfile: reduce image size by tracing imports, copy only needed files, fix sharp errors, and build minimal production Docker images…"
---

**Summary Triples**
- (next.config.ts, must set, output: "standalone" to enable import tracing and produce a minimal server bundle)
- (next build (when output is standalone), produces, .next/standalone which contains a minimal package.json, server files, and trimmed node_modules)
- (Dockerfile pattern, should be, multi-stage: builder (build app) -> final (copy .next/standalone + public + static))
- (final image, needs only, .next/standalone contents, public, .next/static and a small Node runtime)
- (sharp errors in production, are caused by, missing native system libs (libvips) or incompatible C library (musl on Alpine) at runtime)
- (fix for sharp on Alpine, options, install libvips + build deps on Alpine OR use a glibc-based base (debian-slim) or use prebuilt sharp binaries)
- (.next/standalone/package.json, is useful for, installing only production dependencies listed by the standalone bundle in the final image)
- (image size savings, achieved by, tracing imports and copying only required node_modules instead of entire node_modules tree)
- (common final base images, recommended, debian-slim (for native modules) or lightweight node base (if you handle system libs))
- (debugging image optimization failures, requires, checking .next/standalone output, verifying required system libs, and confirming built artifacts copied into final stage)

### {GOAL}
Next.js standalone Dockerfile: reduce image size by tracing imports, copy only needed files, fix sharp errors, and build minimal production Docker images…

### {PREREQS}
- Access to Next.js 16
- Access to Node.js 20
- Access to Docker
- Access to Alpine Linux
- Access to npm

### {STEPS}
1. Enable standalone output in config
2. Install dependencies in deps stage
3. Build app to generate standalone files
4. Copy public and static assets
5. Install native modules in runner
6. Create non-root user and set permissions
7. Use minimal base image and expose port

<!-- llm:goal="Next.js standalone Dockerfile: reduce image size by tracing imports, copy only needed files, fix sharp errors, and build minimal production Docker images…" -->
<!-- llm:prereq="Access to Next.js 16" -->
<!-- llm:prereq="Access to Node.js 20" -->
<!-- llm:prereq="Access to Docker" -->
<!-- llm:prereq="Access to Alpine Linux" -->
<!-- llm:prereq="Access to npm" -->
<!-- llm:output="Completed outcome: Next.js standalone Dockerfile: reduce image size by tracing imports, copy only needed files, fix sharp errors, and build minimal production Docker images…" -->

# Ultimate Next.js Standalone Dockerfile Guide (Tiny Images)
> Next.js standalone Dockerfile: reduce image size by tracing imports, copy only needed files, fix sharp errors, and build minimal production Docker images…
Matija Žiberna · 2026-03-02

I kept seeing Dockerfiles for Next.js 16 that were either 2GB heavy or missing critical production optimizations. After debugging my third "why is image optimization failing in production" error, I finally sat down to understand exactly what `output: "standalone"` does under the hood. Here's what I learned.

## What It Is
A production-grade Next.js Dockerfile isn't just about getting the app to run. It's about stripping away the massive `node_modules` directory that you *don't* need and keeping only the tiny subset of files you *do*.
In Next.js 16, this is powered by **Output Standalone**. When you enable this, Next.js traces every import in your application and copies only the necessary files from `node_modules` into a `.next/standalone` directory.
Instead of shipping your entire development dependency tree to production, you ship a calculated, minimal server.
## Mental Model: The Surgeon vs. The Mover
Think of a standard Docker build like hiring a moving company. They pack *everything* in your house—every dusty box, every broken chair—and ship it to the new place. It works, but it's expensive and slow.
Think of `output: "standalone"` like a surgeon. It operates with precision, cutting out exactly the tissue (code) needed to keep the patient (app) alive and leaving everything else behind.
Your `node_modules` might differ by 500MB between these two approaches.
## Configure It First
Before touching Docker, you must enable this in your specific Next.js config. It does not happen by default.
```typescript
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
  output: "standalone",
  // ... other config
};
export default nextConfig;
```
## The "Perfect" Dockerfile (Reference)
Here is the multi-stage pattern that works for Next.js 16.
```dockerfile
# 1. Base image (use Alpine for size)
FROM node:20-alpine AS base
# 2. Dependencies - install only what's needed for install
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Copy package managers
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN npm ci
# 3. Builder - rebuild the source code
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Run the build (creating .next/standalone)
RUN npm run build
# 4. Runner - the final production image
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
# Don't run as root
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# KEY STEP: Install Sharp in the runner
# Standalone build does NOT bundle sharp automatically
RUN npm install sharp
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]
```
## When To Use It
Use this pattern when you are **Self-Hosting**.
- Deploying to a VPS (Hetzner, DigitalOcean)
- Deploying to a container platform (Fly.io, Cloud Run, Railway)
- Deploying to Kubernetes
If you are paying for compute by the GB of RAM or storage, this optimization pays for itself immediately.
## When NOT To Use It
Do not use this if you are deploying to **Vercel**. Vercel's build pipeline handles strict output tracing and optimization automatically. You adding a Dockerfile there is redundant.
Also, avoid `standalone` if you are using a custom server (e.g., `server.js` with Express). The tracing logic in Next.js does not automatically trace dependencies required by your custom server entry point.
## Gotchas & Common Mistakes
### 1. The "Sharp is Missing" Error
You'll likely see this error in your logs:
`Error: 'sharp' is required to be installed in standalone mode for the image optimization to function correctly`
**Why:** The `standalone` trace includes your *code*, but `sharp` is a native module that often gets excluded or has architecture mismatches (e.g., built on Mac M1, running on Linux Alpine).
**Fix:** You must explicitly `npm install sharp` inside the **runner** stage, or ensure the architecture matches exactly. The specific `RUN npm install sharp` line in the Dockerfile above handles this.
### 2. Missing CSS or Images
If your app loads but styles are broken or images 404, you forgot to copy the assets.
**Why:** The `standalone` folder contains logic, but it does *not* contain your `public` folder or the compiled static assets (`.next/static`).
**Fix:** You must manually `COPY` both of these folders from the builder stage to the runner stage.
```dockerfile
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static
```
### 3. Permissions Hell
Running as `root` inside Docker is a security risk. But running as `nextjs` often leads to `EACCES` errors when Next.js tries to write to the ISR cache.
**Why:** The `.next` directory needs to be writable by the user running the process.
**Fix:** Create the user/group explicitly and `chown` the directories.
```dockerfile
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
RUN chown nextjs:nodejs .next
```
## Conclusion
The `output: "standalone"` mode in Next.js 16 is powerful, but it requires you to respect its boundaries. It gives you a surgically precise production artifact, but it relies on you to stitch the patient back together (copying assets, installing native modules) correctly.
If you control your own infrastructure, this is the only way to fly.
Thanks, Matija

## LLM Response Snippet
```json
{
  "goal": "Next.js standalone Dockerfile: reduce image size by tracing imports, copy only needed files, fix sharp errors, and build minimal production Docker images…",
  "responses": [
    {
      "question": "What does the article \"Ultimate Next.js Standalone Dockerfile Guide (Tiny Images)\" cover?",
      "answer": "Next.js standalone Dockerfile: reduce image size by tracing imports, copy only needed files, fix sharp errors, and build minimal production Docker images…"
    }
  ]
}
```