I came across this issue while trying to use puppeteer on Vercel.\n\n## Solution\nWhat seems to work for now is explicitly defining the file tracings in next.config.ts and adding a fallback in the function logic.\n\n### 1. Update next.config.ts\ntsx\nimport type { NextConfig } from "next";\n\nconst nextConfig: NextConfig = {\n serverExternalPackages: ["@sparticuz/chromium", "puppeteer-core"],\n outputFileTracingIncludes: {\n "/api/print/route": ["node_modules/@sparticuz/chromium/bin/"],\n "/api/print": ["node_modules/@sparticuz/chromium/bin/"],\n },\n};\n\nexport default nextConfig;\n\n\n### 2. Implementation with Fallback\nExplicitly defining the file tracings and also adding a fallback:\n\ntsx\n// Find the correct path for the chromium binaries\nlet executablePath = "";\ntry {\n // Try to find it in the expected location for Vercel\n const binPath = path.join(\n process.cwd(),\n "node_modules/@sparticuz/chromium/bin",\n );\n if (fs.existsSync(binPath)) {\n executablePath = await chromium.executablePath(binPath);\n } else {\n // Fallback to default which might work if not bundled\n executablePath = await chromium.executablePath();\n }\n} catch (e) {\n console.error("Error resolving executable path:", e);\n // Last resort fallback\n executablePath = await chromium.executablePath();\n}\n
Thanks for sharing the workaround. The next.config.ts file tracing approach works, but it’s undocumented and breaks whenever Next.js changes its bundling behavior (which happens more often than
you’d think).
For anyone reading this who doesn’t want to maintain that config, there are alternatives that avoid the Chromium binary problem entirely:
- Client-side: jsPDF or html2pdf.js for simple PDFs (limited CSS support, but zero server deps)
- https://gotenberg.dev — open source, self-hosted. Run Chromium in a Docker container and call it via HTTP from your serverless function. Full quality, you manage the infra.
- https://pdfshift.io — hosted API with a free tier.
- https://presa.dev — hosted API I built, also has a free tier (100 PDFs/month).
The Chromium-on-serverless approach will keep breaking with every Node/Next.js/Chromium version bump. An HTTP call doesn’t have that problem.