Skip to content

🚀 Add one-click Render deployment via render.yaml Blueprint#2275

Open
Ho1yShif wants to merge 9 commits intofastapi:masterfrom
Ho1yShif:contribute-render-deploy
Open

🚀 Add one-click Render deployment via render.yaml Blueprint#2275
Ho1yShif wants to merge 9 commits intofastapi:masterfrom
Ho1yShif:contribute-render-deploy

Conversation

@Ho1yShif
Copy link
Copy Markdown

@Ho1yShif Ho1yShif commented May 7, 2026

Summary

  • One-click Render deployment via a new render.yaml Blueprint and a Deploy to Render button in the README — 100% free tier to start (FastAPI backend on Docker runtime, Vite static frontend, Postgres database, shared fastapi-env env group). Free Postgres expires after 90 days unless upgraded; web services and the env group stay free indefinitely.
  • Backend reuses the existing backend/Dockerfile; new backend/scripts/start.sh wrapper runs migrations + initial-data seed, then execs fastapi so SIGTERM reaches uvicorn directly.
  • Frontend deploys as a static site via Bun build (no Docker), with SPA rewrite to index.html.
  • Removes the self-hosted Docker Compose deploy workflows — Render auto-deploys on push to master.

Test plan

  • Click the Deploy to Render button, fill the placeholder env vars in the fastapi-env group, confirm both services come up and login works after setting VITE_API_URL / FRONTEND_HOST.

🤖 Generated with Claude Code

Ho1yShif and others added 9 commits May 7, 2026 11:08
Add render.yaml provisioning a FastAPI Docker web service, a Vite/Bun
static site, and a managed Postgres database. Migrations run on container
startup via prestart.sh (preDeployCommand isn't supported on free tier).
Render auto-deploys on push to master, replacing the self-hosted runner
workflows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add the one-click Deploy to Render button to the README pointing at this
repo's Blueprint. Restructure render.yaml so the backend, frontend, and
Postgres are nested under a `full-stack-fastapi-template` project with a
`production` environment, making the resources easier to find and manage
together in the Render Dashboard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous `dockerCommand: bash scripts/prestart.sh && fastapi run ...`
ran prestart but never reached the fastapi server because Render's Docker
runtime executes dockerCommand as exec form, so the `&&` was passed as a
literal arg instead of being interpreted by a shell. Move the backend to
the starter plan so preDeployCommand is available, and run prestart.sh
there — migrations now execute once per deploy in a dedicated job
instead of on every container restart.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Render build failed in vite config load with `z.function(...).returns
is not a function` because @tanstack/router-plugin@1.153.2 (resolved from
the loose ^1.140.0 constraint) bundles a router-generator that calls a
zod v3 API removed in zod v4. Bump router-plugin to ^1.166.7 to match
the rest of the @tanstack/* packages and pull in a zod-v4-compatible
generator. routeTree.gen.ts is regenerated by the new plugin.

Also simplify the static-site buildCommand: this is a Bun workspace with
the lockfile at the repo root, so install at the root with
--frozen-lockfile and build the frontend via `bun run --filter frontend
build`. Render's static runtime ships Bun by default, so the manual curl
install step is no longer needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The earlier `dockerCommand: bash scripts/prestart.sh && fastapi run ...`
failed because Render's Docker runtime executes dockerCommand as exec
form (ARGV split on whitespace), so `&&` was passed as a literal arg
and fastapi never started. Stop-gap was bumping to the starter plan to
get preDeployCommand. Now: drop a thin wrapper at scripts/start.sh that
runs prestart then `exec`s fastapi, and invoke it as a single
no-shell-features command. Lets us go back to the free plan with no
parsing ambiguity, and `exec` makes fastapi PID 1 so SIGTERM hits it
directly during shutdown.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pull all non-database env vars (plain values, generated SECRET_KEY, and
sync: false placeholders) into a top-level envVarGroups block named
fastapi-env. Both the backend and frontend services reference it via
fromGroup, so users have one place to fill in secrets instead of two.
POSTGRES_* stay on the backend service because fromDatabase isn't
supported inside groups.

Update the README's Deploy-to-Render setup steps to walk through the
env-group flow, including the loop-back step where users return to set
VITE_API_URL, FRONTEND_HOST, and BACKEND_CORS_ORIGINS once both
services have their .onrender.com URLs assigned.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mark VITE_API_URL as a frontend (build-time) var and FRONTEND_HOST /
BACKEND_CORS_ORIGINS as backend (runtime) vars. They all live in the
same fastapi-env group, so users still set them in one place, but
knowing which service reads each one makes it easier to predict which
service needs to redeploy after a change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
For the upstream PR: replace the fork URL (Ho1yShif/...) with the
canonical fastapi/full-stack-fastapi-template URL in render.yaml's
`repo:` fields and the README's Deploy to Render button.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Clarify in the README setup steps that POSTGRES_* are set directly on
the backend service (via fromDatabase) and won't appear on the
fastapi-env group page, since Render's env groups don't support
fromDatabase. They're still picked up by the app at runtime — the
split is purely organizational in the Dashboard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants