Skip to content

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.

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.

  • 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.
  1. In the Render dashboard, choose New → Blueprint and select your repository. Render reads render.yaml from the repository root.

  2. Fill in the values Render prompts for. These are the sync: false variables, shared by the backend, workers and scheduler:

    Variable Value
    APP_BASE_URL The static site’s URL, e.g. https://plainwright.onrender.com. Render shows it once the site exists; you can correct it afterwards.
    CORS_ORIGINS The same URL.
    S3_ENDPOINT_URL For R2: https://<account-id>.r2.cloudflarestorage.com. Empty for AWS S3.
    S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY Your bucket and its access key.
    S3_PUBLIC_BASE_URL Optional public bucket or CDN URL. Empty serves artifacts through short-lived presigned URLs.
    ANTHROPIC_API_KEY Optional server-wide fallback model. Users can add their own providers instead.
    SENTRY_DSN Optional, for error reporting.
    SMTP_HOST, SMTP_USER, SMTP_PASSWORD, SMTP_FROM Optional, for invitations, password reset and alert emails. SMTP_PORT defaults to 587 with STARTTLS.
  3. Apply the blueprint and wait for every service to deploy. plainwright-mcp installs the MCP server and Chromium on each start, so it comes up last.

  4. 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/* to https://plainwright-backend.onrender.com. If your backend URL differs, edit the two routes destinations in render.yaml, commit, and sync the blueprint.
    • The MCP service’s internal address (plainwright-mcp → Connect → Internal). If it isn’t plainwright-mcp:8931, update PLAYWRIGHT_MCP_URL in the plainwright-shared group.
  5. Open the static site URL and create the first account.

  • Decide on /metrics. The backend web service has its own public onrender.com URL. In production mode /metrics answers 404 until you add a METRICS_TOKEN to the plainwright-shared group; add one if you want to scrape it. See Monitoring.
  • Add sign-in providers by setting GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET or GITHUB_CLIENT_ID/GITHUB_CLIENT_SECRET on 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 numInstances and, to match, the plainwright-mcp plan (a 2 GB instance handles two or three concurrent browsers). See Scaling workers.
  • Back up with Render’s Postgres backups, or pg_dump against the database’s external connection string. See Upgrades, migrations and backups.
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.