Puppeteer is the go-to for PDF generation in Node.js, but it breaks when you deploy to Vercel. Chromium's binary is too large for standard serverless bundles, Edge Functions block native modules entirely, and cold starts under concurrent load are painful. A REST API sidesteps every constraint: it's just a fetch call.
App Router: Route Handler
export async function POST(request: Request) {
const { html } = await request.json() as { html: string }
const apiRes = await fetch('https://platform.htmltopdfapi.co/api/v1/pdf/generate', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.HTMLTOPDF_API_KEY!}`,
'Content-Type': 'application/json',
Accept: 'application/pdf',
},
body: JSON.stringify({ html, paper_size: 'a4' }),
cache: 'no-store',
})
if (!apiRes.ok) {
return Response.json({ error: 'PDF generation failed' }, { status: 500 })
}
return new Response(await apiRes.arrayBuffer(), {
headers: {
'Content-Type': 'application/pdf',
'Content-Disposition': 'inline; filename="document.pdf"',
},
})
}Pages Router: API Route
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') return res.status(405).end()
const { html } = req.body as { html: string }
const apiRes = await fetch('https://platform.htmltopdfapi.co/api/v1/pdf/generate', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.HTMLTOPDF_API_KEY}`,
'Content-Type': 'application/json',
Accept: 'application/pdf',
},
body: JSON.stringify({ html, paper_size: 'a4' }),
})
if (!apiRes.ok) return res.status(500).json({ error: 'PDF generation failed' })
res.setHeader('Content-Type', 'application/pdf')
res.setHeader('Content-Disposition', 'inline; filename="document.pdf"')
res.send(Buffer.from(await apiRes.arrayBuffer()))
}Server Action
For form-driven PDF generation, a Server Action keeps everything server-side:
'use server'
export async function generatePdf(html: string): Promise<ArrayBuffer> {
const res = await fetch('https://platform.htmltopdfapi.co/api/v1/pdf/generate', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.HTMLTOPDF_API_KEY!}`,
'Content-Type': 'application/json',
Accept: 'application/pdf',
},
body: JSON.stringify({ html, paper_size: 'a4' }),
cache: 'no-store',
})
if (!res.ok) throw new Error('PDF generation failed')
return res.arrayBuffer()
}Works on Every Runtime
Because this is fetch(), a standard Web API, it runs identically on Vercel Node.js functions, Edge Functions, Cloudflare Workers, and local development. No binary, no build configuration, no Lambda layer. See the dashboard PDF export guide for a complete Next.js API route implementation.