• Home
BuildWithMatija
Get In Touch
  1. Home
  2. Blog
  3. Docker
  4. Ultimate Next.js Standalone Dockerfile Guide (Tiny Images)

Ultimate Next.js Standalone Dockerfile Guide (Tiny Images)

Use output: "standalone" to trim node_modules, fix sharp/image errors, and build minimal Next.js Docker images

2nd March 2026·Updated on:22nd February 2026·MŽMatija Žiberna·
Docker
Ultimate Next.js Standalone Dockerfile Guide (Tiny Images)

🐳 Docker & DevOps Implementation Guides

Complete Docker guides with optimization techniques, deployment strategies, and automation prompts to streamline your containerization workflow.

No spam. Unsubscribe anytime.

Related Posts:

  • •Deploy Next.js 16 to Netlify - SSR Guide for Builder.io
  • •Next.js 16 Self-Hosted Alternatives: Fly.io, Cloud Run, VPS
  • •Vercel Neon Setup for Next.js: 3-Tier Enterprise Guide

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.

// 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.

# 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.

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.

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

📄View markdown version
0

Frequently Asked Questions

Comments

Leave a Comment

Your email will not be published

Stay updated! Get our weekly digest with the latest learnings on NextJS, React, AI, and web development tips delivered straight to your inbox.

10-2000 characters

• Comments are automatically approved and will appear immediately

• Your name and email will be saved for future comments

• Be respectful and constructive in your feedback

• No spam, self-promotion, or off-topic content

Matija Žiberna
Matija Žiberna
Full-stack developer, co-founder

I'm Matija Žiberna, a self-taught full-stack developer and co-founder passionate about building products, writing clean code, and figuring out how to turn ideas into businesses. I write about web development with Next.js, lessons from entrepreneurship, and the journey of learning by doing. My goal is to provide value through code—whether it's through tools, content, or real-world software.

You might be interested in

Deploy Next.js 16 to Netlify - SSR Guide for Builder.io
Deploy Next.js 16 to Netlify - SSR Guide for Builder.io

21st January 2026

Next.js 16 Self-Hosted Alternatives: Fly.io, Cloud Run, VPS
Next.js 16 Self-Hosted Alternatives: Fly.io, Cloud Run, VPS

26th February 2026

Vercel Neon Setup for Next.js: 3-Tier Enterprise Guide
Vercel Neon Setup for Next.js: 3-Tier Enterprise Guide

3rd February 2026

Table of Contents

  • What It Is
  • Mental Model: The Surgeon vs. The Mover
  • Configure It First
  • The "Perfect" Dockerfile (Reference)
  • When To Use It
  • When NOT To Use It
  • Gotchas & Common Mistakes
  • 1. The "Sharp is Missing" Error
  • 2. Missing CSS or Images
  • 3. Permissions Hell
  • Conclusion
On this page:
  • What It Is
  • Mental Model: The Surgeon vs. The Mover
  • Configure It First
  • The "Perfect" Dockerfile (Reference)
  • When To Use It
Build With Matija Logo

Build with Matija

Matija Žiberna

I turn scattered business knowledge into one usable system. End-to-end system architecture, AI integration, and development.

Quick Links

Payload CMS Websites
  • Bespoke AI Applications
  • Projects
  • How I Work
  • Blog
  • Get in Touch

    Have a project in mind? Let's discuss how we can help your business grow.

    Contact me →
    © 2026BuildWithMatija•Principal-led system architecture•All rights reserved