Deploy to Render
The repository ships a Render Blueprint, render.yaml, that creates the whole stack in one go: Postgres, Redis, the API, workers, the scheduler, a private Chromium service and the web app. Use it when you want managed hosting and no servers to look after. The trade-offs: services can’t share a disk, so screenshots go to object storage and project file uploads aren’t available, and only Chromium is set up.
What the blueprint creates
Section titled “What the blueprint creates”| Name | Render type | Plan | Role |
|---|---|---|---|
plainwright |
Static site | — | The React build. Rewrites /api/* and /screenshots/* to the backend and everything else to index.html, and sets security headers. This is the URL people open. |
plainwright-backend |
Web service (Docker, backend/Dockerfile) |
starter |
The API. Runs migrations on start; health check /health. |
plainwright-worker |
Background worker (Docker, backend/Dockerfile.worker) |
standard × 2 |
Runs tests, one at a time per instance. Raise numInstances for more parallel runs. |
plainwright-scheduler |
Background worker (Docker) | starter |
Cron-scheduled runs and the stuck-run reaper. Keep exactly one. |
plainwright-mcp |
Private service (image mcr.microsoft.com/playwright:v1.44.0-jammy) |
standard |
Headless Chromium behind Playwright MCP, with the same flags as Docker Compose. Chromium wants at least 2 GB of RAM. |
plainwright-redis |
Key Value | starter |
The job queue. maxmemoryPolicy: noeviction, private network only. |
plainwright-db |
Postgres 15 | basic-256mb |
All data. Database testai_db, user testai. |
plainwright-shared |
Environment group | — | Settings every app service shares, including a generated SECRET_KEY, PLAINWRIGHT_ENV=production, STORAGE_BACKEND=s3, LOG_FORMAT=json, BILLING_ENABLED=false and PLAYWRIGHT_MCP_URL. |
Render generates SECRET_KEY once, as a long random value, and the backend runs in
production mode: it refuses to start if that key is
ever emptied or replaced with a weak one. Never edit the generated key in place; to change it, use
the rotation command.
None of these plans is free. Check Render’s pricing before you apply the blueprint, and scale the worker and MCP plans to the number of parallel runs you need.
Before you start
Section titled “Before you start”- Your own copy of the repository on GitHub or GitLab, connected to Render. A fork works.
- An S3-compatible bucket and an access key with read and write access to it. Cloudflare R2 is a good fit because it charges no egress fees. See Object storage for how to create one.
Deploy
Section titled “Deploy”-
In the Render dashboard, choose New → Blueprint and select your repository. Render reads
render.yamlfrom the repository root. -
Fill in the values Render prompts for. These are the
sync: falsevariables, shared by the backend, workers and scheduler:Variable Value APP_BASE_URLThe static site’s URL, e.g. https://plainwright.onrender.com. Render shows it once the site exists; you can correct it afterwards.CORS_ORIGINSThe same URL. S3_ENDPOINT_URLFor R2: https://<account-id>.r2.cloudflarestorage.com. Empty for AWS S3.S3_BUCKET,S3_ACCESS_KEY_ID,S3_SECRET_ACCESS_KEYYour bucket and its access key. S3_PUBLIC_BASE_URLOptional public bucket or CDN URL. Empty serves artifacts through short-lived presigned URLs. ANTHROPIC_API_KEYOptional server-wide fallback model. Users can add their own providers instead. SENTRY_DSNOptional, for error reporting. SMTP_HOST,SMTP_USER,SMTP_PASSWORD,SMTP_FROMOptional, for invitations, password reset and alert emails. SMTP_PORTdefaults to 587 with STARTTLS. -
Apply the blueprint and wait for every service to deploy.
plainwright-mcpinstalls the MCP server and Chromium on each start, so it comes up last. -
Check the two names Render may have changed. Render adds a suffix when a name is taken.
- The backend’s public URL. The static site rewrites
/api/*and/screenshots/*tohttps://plainwright-backend.onrender.com. If your backend URL differs, edit the tworoutesdestinations inrender.yaml, commit, and sync the blueprint. - The MCP service’s internal address (plainwright-mcp → Connect → Internal). If it isn’t
plainwright-mcp:8931, updatePLAYWRIGHT_MCP_URLin theplainwright-sharedgroup.
- The backend’s public URL. The static site rewrites
-
Open the static site URL and create the first account.
After the first deploy
Section titled “After the first deploy”- Decide on
/metrics. The backend web service has its own publiconrender.comURL. In production mode/metricsanswers 404 until you add aMETRICS_TOKENto theplainwright-sharedgroup; add one if you want to scrape it. See Monitoring. - Add sign-in providers by setting
GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRETorGITHUB_CLIENT_ID/GITHUB_CLIENT_SECRETon the backend. The callback URL to register is<APP_BASE_URL>/api/oauth/google/callback(or/github/callback); it goes through the static site’s/api/*rewrite. See Sign-in and email. - Scale by raising the worker’s
numInstancesand, to match, theplainwright-mcpplan (a 2 GB instance handles two or three concurrent browsers). See Scaling workers. - Back up with Render’s Postgres backups, or
pg_dumpagainst the database’s external connection string. See Upgrades, migrations and backups.
Limitations on Render
Section titled “Limitations on Render”| Limitation | Why | Workaround |
|---|---|---|
| No project file uploads for browser tests | The browser would need the same disk as the backend, and Render services don’t share disks. | Run browser tests that upload files on a Docker Compose install. |
| Chromium only | The blueprint creates one browser service. | Add private services like plainwright-mcp with --browser firefox or --browser webkit, and set PLAYWRIGHT_MCP_URL_FIREFOX / PLAYWRIGHT_MCP_URL_WEBKIT. |
| The live run view can lag | Live events stream through the static site’s rewrite, which may buffer them. | Runs still finish normally; the result appears when the run ends. |
| Local storage isn’t available | Each service has its own disk. | The blueprint sets STORAGE_BACKEND=s3; keep it. |
Next steps
Section titled “Next steps”- Configuration: everything else you can set in the environment group.
- CI webhook and gates: trigger runs after each deploy.
- Security model: what to configure before inviting a team.