Deploy a service to Render
tapestry deploy creates a Render service for the current repo in one command — repo link, branch, build/start commands, plan, and the shared env group — using Render’s REST API. It removes the per-project dashboard clicking that setting up a new service otherwise takes.
This guide covers the imperative, per-project path. For the platform’s own multi-service stack (staging, the observability services), use the declarative render.yaml Blueprint instead — see Set up Render and the decision record ADR 0005 for when to use which.
Before you start
Section titled “Before you start”-
A Render API key. Generate one at Render dashboard → avatar → Account Settings → API Keys, then export it:
Terminal window export RENDER_API_KEY=rnd_...(Or pass
--api-keyon the command.) -
The GitHub ↔ Render connection. Render’s GitHub App must already be authorized for the repo you are deploying. This is a one-time dashboard step; there is no API for it. If you have deployed any service from this repo before, it is already done.
-
The CLI installed.
pip install tapestry-cli(or run frompackages/cli/).
Step 1 — preview with --dry-run
Section titled “Step 1 — preview with --dry-run”Always preview first. --dry-run prints the exact request body that would be sent and makes no API calls — it needs no API key:
tapestry deploy --name my-service --type web \ --build "pip install -r requirements.txt" \ --start "uvicorn main:app --host 0.0.0.0 --port $PORT" \ --dry-runSecret values are masked ("***") in dry-run output, so you can paste it safely.
Step 2 — create the service
Section titled “Step 2 — create the service”Drop --dry-run to send it:
tapestry deploy --name my-service --type web \ --build "pip install -r requirements.txt" \ --start "uvicorn main:app --host 0.0.0.0 --port $PORT" \ --plan starter --region oregon \ --env-group tapestry-shared-secretsWhat it does, in order:
- Loads the deploy spec (
deploy/render-service.jsonby default; flags override it). - Resolves the repo URL from
git origin(unless--repois given). - Resolves the Render owner id via
GET /v1/owners(unless--owner-id/--owner-nameis given). - Idempotency: checks
GET /v1/services?name=<name>— if a service with that exact name already exists, it stops without creating a duplicate. - Creates the service (
POST /v1/services) with the repo link, branch, auto-deploy, and build/start commands. - Attaches the named env group, if you passed
--env-group. - Prints the new service’s URL.
Committing a spec instead of passing flags
Section titled “Committing a spec instead of passing flags”Repeated flags belong in a committed spec so the deploy is reproducible. Create deploy/render-service.json:
{ "name": "my-service", "type": "web", "runtime": "python", "plan": "starter", "region": "oregon", "build": "pip install -r requirements.txt", "start": "uvicorn main:app --host 0.0.0.0 --port $PORT", "healthCheckPath": "/health", "envGroup": "tapestry-shared-secrets"}Then just run tapestry deploy (flags still override the spec when you need a one-off change).
Secrets
Section titled “Secrets”--set KEY=VALUE— a plain (non-secret) env var, repeatable.--secret KEY— a secret env var whose value is read from your own environment by that name at deploy time, repeatable. The name is committed; the value never is. In--dry-runoutput the value is masked.
For secrets shared across services, prefer the env group (--env-group tapestry-shared-secrets) over per-service --secret.
Supported service types
Section titled “Supported service types”--type accepts web, cron, worker, and private. Static sites are not supported by this command (they need a publishPath and have no start command) — create those from the Render dashboard or a Blueprint.
Cron services also need --schedule (a cron expression).
If it fails
Section titled “If it fails”error: no Render API key— exportRENDER_API_KEYor pass--api-key. (Not needed for--dry-run.)- Owner could not be resolved / multiple owners — pass
--owner-id(or--owner-name) to disambiguate. - The service already exists — that is the idempotency guard, not an error; the command stops rather than duplicating. Rename with
--nameor manage the existing service in the dashboard. - Build/deploy fails on Render after creation — that is a Render-side build issue, not the CLI; check the service’s logs in the Render dashboard.
See also
Section titled “See also”- CLI commands reference — every
tapestrysubcommand and flag. - Set up Render — the account setup, env groups, and the declarative Blueprint path.