Background
I use Playwright in my API to render email templates for my app, Snap Template.
It worked fine on my computer—insert “works on my machine” meme here—but after deploying to Render, the export feature failed because Playwright could not find the Chromium executable.
The deployment itself completed successfully. The failure occurred at runtime when the API attempted to launch Chromium.
Root Cause
Locally, I had previously run:
npx playwright install
That downloaded the browser binaries into Playwright’s cache on my computer.
The Render environment did not have the same local cache, so although the Playwright package was installed, the Chromium executable it expected was missing.
Playwright normally stores browsers in an operating-system-specific cache. On Linux, that defaults to:
~/.cache/ms-playwright
The location can be changed using PLAYWRIGHT_BROWSERS_PATH.
The Fix That Worked
1. Install Chromium During postinstall
I added the following script to package.json:
{
"scripts": {
"postinstall": "playwright install chromium",
"build": "your-build-command"
}
}
This installs only Chromium rather than downloading every browser supported by Playwright.
Because my API launches Playwright in production, the relevant Playwright package also needs to be inside dependencies, not only devDependencies:
{
"dependencies": {
"playwright": "your-installed-version"
}
}
Production dependencies are packages required for the deployed application to run, while development dependencies are intended for development and testing tools that are not needed at runtime.
2. Use a Render Build Command
My Render build command can now be:
npm ci && npm run build
Or, when the project does not have a suitable lockfile:
npm install && npm run build
There is no need to add npm run postinstall manually:
npm install && npm run postinstall && npm run build
npm automatically runs lifecycle scripts such as postinstall as part of the installation process. Running it again would download or verify the browser installation twice.
Alternatively, you can remove the postinstall script and make the browser installation explicit:
npm ci && npx playwright install chromium && npm run build
Either approach is valid. I used postinstall so the browser installation remains part of the dependency setup.
3. Configure the Browser Path
In Render, I added:
PLAYWRIGHT_BROWSERS_PATH=/opt/render/project/.cache/playwright
The important part is not that every host must use this exact path. The important part is that the same PLAYWRIGHT_BROWSERS_PATH value is available during both:
- Browser installation
- Application runtime
This tells Playwright where to install Chromium and where to look for it later. Playwright officially supports overriding its default browser cache with this environment variable.
For a more portable project-local installation, Playwright also supports:
PLAYWRIGHT_BROWSERS_PATH=0
This stores the browsers under:
node_modules/playwright-core/.local-browsers
That is known as a hermetic installation.
Why It Works
The corrected deployment flow is:
- Render installs the project dependencies.
- npm automatically runs
postinstall. - Playwright downloads the Chromium version expected by the installed package.
- Chromium is stored at the configured browser path.
- The API starts with the same environment variable.
- Playwright finds and launches the installed executable.
Missing Browser vs Missing System Libraries
This fix addresses a missing Chromium executable.
If the error changes to missing shared libraries or operating-system dependencies, the browser is installed but the environment does not contain everything required to launch it.
Playwright can install browser dependencies using:
npx playwright install --with-deps chromium
However, installing system packages may require permissions that are not available in every managed hosting environment. Playwright documents --with-deps as the combined browser and operating-system dependency installation command.
When native deployment does not provide the required libraries, Docker gives you more control over the runtime environment.
Using Docker Instead
For more reproducible deployments, Playwright provides Docker images containing browser binaries and required system dependencies.
Pin the image to the Playwright version used by your project:
FROM mcr.microsoft.com/playwright:vX.Y.Z-noble
Replace vX.Y.Z with the version matching your installed Playwright package.
Avoid using:
FROM mcr.microsoft.com/playwright:latest
A version mismatch can mean the container has different browser binaries from those expected by the package.
The Playwright Docker image contains browsers and operating-system dependencies, but your application still needs to install its npm dependencies.
Extra Checks and Good Practices
Check the Installed Playwright Version
npx playwright --version
Each Playwright release expects specific browser versions, so reinstall the browsers after upgrading Playwright.
Log the Resolved Executable Path
A temporary debug log can confirm where Playwright expects Chromium:
import { chromium } from "playwright";
console.log(
"Chromium executable:",
chromium.executablePath()
);
Remove or reduce diagnostic logging once the deployment is stable.
Check the Installed Browsers
npx playwright install --list
This can help confirm whether Chromium was installed and where Playwright found it.
Monitor Disk Usage
Playwright browser installations can consume hundreds of megabytes, so monitor the service’s storage and build logs.
Install Only What You Need
Installing Chromium directly is already enough to avoid downloading Firefox and WebKit:
npx playwright install chromium
For strictly headless workloads, Playwright also provides an --only-shell option that can avoid downloading the full Chromium browser:
npx playwright install --only-shell chromium
Whether that option is appropriate depends on how your application launches and uses Chromium.
Install During Build, Not on Request
Do not download Chromium when a user requests an export.
Installing during runtime would:
- Increase response and cold-start time
- Add an external network dependency to the request
- Risk concurrent downloads
- Make failures harder to diagnose
Install the browser during the deployment build instead.
Checklist
- Is Playwright in
dependencieswhen it is used by the production API? - Did
postinstallrun during the Render build? - Did the build log show Chromium being downloaded?
- Is
PLAYWRIGHT_BROWSERS_PATHavailable during both build and runtime? - Does
chromium.executablePath()point to an existing file? - Does the Playwright package version match the installed browser?
- If Chromium exists, are Linux system libraries missing instead?
- Would a pinned Playwright Docker image provide a more reliable environment?
Closing Notes
If Playwright works locally but fails after deployment, remember that the npm package and browser binaries are separate.
My local machine already had Chromium inside Playwright’s cache, while the Render service did not. Installing Chromium during the build and configuring a consistent PLAYWRIGHT_BROWSERS_PATH solved the runtime error for Snap Template.
The final setup was:
{
"scripts": {
"postinstall": "playwright install chromium"
}
}
npm ci && npm run build
PLAYWRIGHT_BROWSERS_PATH=/opt/render/project/.cache/playwright
If this helped you do the Playw-right thing and get your service running, share what deployment setup worked for you.
TL;DR
If Playwright works locally but fails on Render with an executable does not exist error:
- Install Chromium during the build.
- Configure
PLAYWRIGHT_BROWSERS_PATHso installation and runtime use the same location. - Make sure Playwright is installed as a production dependency.
- Avoid running the
postinstallscript twice.
Playwright requires browser binaries that match the installed Playwright version. Installing the npm package alone does not guarantee that Chromium is available in the deployed environment.



Top comments (0)