Rendral

Stack · Supabase Edge Functions

Generate PDFs in Supabase Edge Functions

Edge Functions run on Deno Deploy — a sandboxed isolate with no filesystem and no ability to spawn a process. Puppeteer and every wkhtmltopdf wrapper are ruled out by the runtime itself, not by preference.

A fetch call is native there. Pull the row from Postgres, build the HTML, POST it, and stream the PDF straight back — or write it to Supabase Storage and hand the client a signed link.

01Call it from Supabase Edge Functions

render.ts
// supabase/functions/invoice-pdf/index.ts
import { createClient } from "jsr:@supabase/supabase-js@2";

Deno.serve(async (req) => {
  const { invoiceId } = await req.json();

  const supabase = createClient(
    Deno.env.get("SUPABASE_URL"),
    Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")
  );

  const { data: invoice } = await supabase
    .from("invoices").select("*").eq("id", invoiceId).single();

  const res = await fetch("https://rendral.com/api/v1/pdf", {
    method: "POST",
    headers: {
      Authorization: "Bearer " + Deno.env.get("RENDRAL_API_KEY"),
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      html: renderInvoice(invoice),
      options: { format: "A4", pageNumbers: true },
    }),
  });

  return new Response(res.body, {
    headers: { "Content-Type": "application/pdf" },
  });
});

Frequently asked

Why can't I run Puppeteer in an Edge Function?

Deno Deploy isolates have no filesystem and can't spawn subprocesses. Chrome needs both, so browser automation isn't possible in that runtime at any size.

Should I store the PDF in Supabase Storage?

For anything a user re-downloads, yes. Upload the response and serve a signed URL — that keeps the function fast and avoids re-rendering the same document.

How do I keep the API key secret?

Set it with supabase secrets set RENDRAL_API_KEY=… and read it via Deno.env.get. It stays server-side and never reaches the browser.

Does this count against function CPU limits?

Barely. Streaming the response body through is I/O rather than CPU, so the isolate stays well within its budget even for long documents.

Related

Start rendering in minutes.

A free tier, five endpoints, and SDKs for Node and Python.