export_resume_pdf returns a download link plus the page count it actually came out
to.
The fallback
Where the browser is missing, the PDF button says so rather than failing silently, andexport_resume_pdf reports the same thing. The fallback produces an identical document:
1
Open the print view
In the resume editor: ⋯ → Open print view. It is a US-Letter page at
/print/<id>, and it is auth-gated like the rest of the app.2
Save as PDF
Your browser’s print dialog → Save as PDF, with margins set to None. The page
already carries the template’s own half-inch margins.
Getting one-click export on a host without it
The renderer checks these paths in order, and uses the first one that exists:PDF_CHROMIUM_PATHPLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH/usr/bin/chromium/usr/bin/chromium-browser/usr/bin/google-chrome/usr/bin/google-chrome-stable/opt/pw-browsers/chromium/chrome-linux/chrome/root/.cache/ms-playwright/chromium/chrome-linux/chrome
PLAYWRIGHT_BROWSERS_PATH or
/root/.cache/ms-playwright.
So on a host where you control the image, installing chromium, fonts-croscore and
fonts-liberation is usually enough, with PDF_CHROMIUM_PATH pointed at the browser if it
lands somewhere unusual.
On Railway specifically, a Dockerfile installing those three packages does produce a
working renderer — but Railway’s healthcheck did not come up on the resulting container,
so it is not the shipped default. If you want one-click PDF and do not want to solve
that, deploy with Compose instead.
PDF_CHROMIUM_PATH is the narrow exception to the one-variable rule: it is a
machine-level fact about the host that the app cannot discover, it is never required, and
self-hosting still needs only DATABASE_URL.