PDF generation in AWS Lambda
The usual approach — packaging chrome-aws-lambda — is a 50 MB layer, a cold start measured in seconds, and a Chromium build you now own the patching of. Calling an API is a few kilobytes of code and no layer at all.
The code
// handler.mjs — API Gateway proxy integration
export const handler = async (event) => {
const { html } = JSON.parse(event.body ?? '{}');
const upstream = await fetch('https://api.pdfcraft.dev/v1/render', {
method: 'POST',
headers: {
authorization: `Bearer ${process.env.PDFCRAFT_API_KEY}`,
'content-type': 'application/json',
},
body: JSON.stringify({ html, options: { printBackground: true } }),
});
if (!upstream.ok) {
const { error } = await upstream.json();
return { statusCode: upstream.status, body: JSON.stringify({ error }) };
}
const pdf = Buffer.from(await upstream.arrayBuffer());
return {
statusCode: 200,
headers: { 'content-type': 'application/pdf' },
// API Gateway requires base64 for binary, and isBase64Encoded is what
// tells it to decode again on the way out.
body: pdf.toString('base64'),
isBase64Encoded: true,
};
};What to watch for
- `isBase64Encoded: true` is not optional. Without it API Gateway returns the base64 text as the body and the browser downloads a file of ASCII.
- API Gateway caps a response at 6 MB. Past that, use `output: "url"` and return the signed URL instead of the bytes.
- Set the function timeout above the render timeout, or Lambda kills the invocation while the render is still in flight and you are billed for both.
Why not run the browser yourself
You can. Puppeteer and Playwright both work, and for a script you run by hand they are the right answer. The cost arrives at the point it becomes a service someone depends on: one long-lived browser per process rather than one per request, a semaphore so four renders do not become forty, a hard timeout that force-closes a hung page before it holds a slot forever, a scheduled restart because Chromium leaks, and a Chromium version you are now responsible for patching.
None of that is hard. All of it is work that has nothing to do with your product, and it fails under concurrency rather than in testing — which is the worst time to discover it.
Other frameworks
- PDF generation in Next.js
- PDF generation in Django
- PDF generation in Ruby on Rails
- PDF generation in Laravel
- PDF generation in Cloudflare Workers
- PDF generation in Supabase Edge Functions
- PDF generation in Spring Boot
- PDF generation in FastAPI
- PDF generation in Express
- PDF generation in ASP.NET Core
- PDF generation in n8n