Secure file uploads in Next.js
Use this guide when your Next.js application accepts uploads through an App Router route handler and you want the upload decision to stay inside your own infrastructure.
If you want the broader Node.js model behind this pattern, read Secure file uploads in Node.js: Beyond Extension and MIME Checks.
Install
Section titled “Install”npm install pompelmi @pompelmi/next-uploadApp Router route handler
Section titled “App Router route handler”import { createNextUploadHandler } from '@pompelmi/next-upload';import { CommonHeuristicsScanner, composeScanners, createZipBombGuard,} from 'pompelmi';
export const runtime = 'nodejs';export const dynamic = 'force-dynamic';
const scanner = composeScanners( [ ['zipGuard', createZipBombGuard()], ['heuristics', CommonHeuristicsScanner], ], { stopOn: 'suspicious' });
export const POST = createNextUploadHandler({ scanner, includeExtensions: ['pdf', 'png', 'jpg', 'jpeg', 'zip'], allowedMimeTypes: [ 'application/pdf', 'image/png', 'image/jpeg', 'application/zip', ], maxFileSizeBytes: 10 * 1024 * 1024, detectMime: true, enforceMime: true, failClosed: true, allowArchives: true, archive: { maxEntries: 512, maxTotalUncompressedBytes: 100 * 1024 * 1024, maxDepth: 1, },});Why this path
Section titled “Why this path”- It keeps scanning inside the Node runtime instead of a cloud API or sidecar service.
- It fits naturally into App Router route handlers.
- It returns structured JSON that can drive UI feedback or object-storage promotion logic.
Next.js-specific notes
Section titled “Next.js-specific notes”- Use the Node runtime for multipart routes.
- Keep uploads out of Server Actions when you need byte-level inspection, archive controls, or predictable route-level error handling.
- Treat the route as the gate; store to S3 or another object store only after the response is
clean.