🚀 How to Run npm run build in Next.js Using a Custom Export Script
If you’ve ever built a Next.js project and wanted a clean static export for deployment, you’ll know that npm run build
is the standard way. But sometimes, you don’t want all the extra files, error pages, or configs bloating your output.
That’s where a custom export script comes in. Today, I’ll walk you through how to use a Bash script to streamline your Next.js build process and get a lean, production-ready static site.
📦 The Problem with a Standard Next.js Build
Running:
npm run build
generates a .next
directory with all the optimized production files. However:
-
It includes unnecessary files.
-
It might ship error pages that break static exports.
-
You don’t always want your entire repo—just what’s needed for a deployable export.
This script solves all that.
⚡ The Custom Build Script
Here’s the script in full:
#!/usr/bin/env bash
set -euo pipefailROOT="$(pwd)"
TMP="$ROOT/.export-tmp"
OUT="$ROOT/out"rm -rf "$TMP" "$OUT"
mkdir -p "$TMP"# Copy only what's needed for a public/static export
rsync -a --prune-empty-dirs \
--include="/app/" \
--include="/app/(public)/***" \
--include="/public/***" \
--include="/styles/***" \
--include="/components/***" \
--include="/lib/***" \
--include="/package.json" \
--include="/yarn.lock" --include="/package-lock.json" --include="/pnpm-lock.yaml" \
--include="/next.config.*" \
--include="/tsconfig.json" --include="/jsconfig.json" \
--include="/postcss.config.*" --include="/tailwind.config.*" \
--exclude="*" \
"$ROOT/" "$TMP/"# Remove error pages that break static export
rm -f "$TMP/app/error.tsx" "$TMP/app/error.js" "$TMP/app/global-error.tsx" "$TMP/app/global-error.js" || truepushd "$TMP" >/dev/null
# install using whatever lockfile you have
if [ -f yarn.lock ]; then yarn install --frozen-lockfile; else npm ci; fi# Build + export just the filtered app
npm run build
popd >/dev/nullmv "$TMP/out" "$OUT"
rm -rf "$TMP"echo "✅ Static export created at: $OUT"
🔍 How It Works
-
Set up directories
It creates a temporary.export-tmp
directory for the build and anout
folder for the final export. -
Selective file copy with rsync
Instead of copying your whole project, it only copies:-
app/
,components/
,lib/
,styles/
-
public/
assets -
Config files (
next.config.js
,tailwind.config.js
,tsconfig.json
, etc.) -
Dependency lockfiles (
yarn.lock
,package-lock.json
, etc.)
Everything else is excluded to keep things lean.
-
-
Remove problematic error pages
Next.js error pages likeapp/error.tsx
can break static exports, so they’re removed. -
Install dependencies & build
-
Uses
yarn install --frozen-lockfile
if ayarn.lock
file exists. -
Falls back to
npm ci
otherwise. -
Runs
npm run build
to generate the production-ready static export.
-
-
Move the final build
The generatedout/
folder is placed at the project root for easy deployment.
✅ Running the Script
Make the script executable:
chmod +x build.sh
Then run:
./build.sh
When it’s done, you’ll see:
✅ Static export created at: ./out
Now your clean static build is ready to deploy 🚀.
🛠️ Why This Approach?
-
Cleaner builds → Only essential files are included.
-
Smaller deploys → Faster uploads to hosting services.
-
Cross-package manager support → Works with
npm
,yarn
, orpnpm
. -
Static-ready → Automatically strips out Next.js error pages that break exports.
🌍 Where to Use This
You can deploy the out/
folder to any static hosting provider:
-
Vercel
-
Netlify
-
GitHub Pages
-
Cloudflare Pages
-
S3 + CloudFront
Final Thoughts
Next.js is powerful, but sometimes the defaults don’t fit every deployment workflow. With this script, you get full control over your npm run build
process, ensuring only the right files make it into production.
- General Articles
- Tech Simplified
- Women in Tech Spotlight
- Digital Safety & Security
- The AI Corner
- The Innovator's Hub (Startups & Projects)
- Gadget Reviews & News
- Crypto & Forex Digest
- The Student's Tech Guide
- The Digital Lifestyle
- "How-To" & Tutorials