Render Tutorials
Advanced render.yaml Blueprint patterns

Putting it all together

⏱ 9 min

You’ve seen each pattern on its own. Now the payoff: a single render.yaml that uses all of them together - projects + environments, env groups, every wiring primitive, previews, a monorepo buildFilter, a disk on a worker, a Docker web service, and an image-runtime cron.

It’s longer than anything you’d write greenfield. Treat it as a reference: scan it, copy the bits that match your shape, and lean on the validation loop from step 01 to keep your version honest.

The composed Blueprint

render.yaml
previews:
generation: automatic
expireAfterDays: 3
projects:
- name: acme-platform
envVarGroups:
- name: shared-config
envVars:
- key: LOG_LEVEL
value: info
- key: NODE_ENV
value: production
environments:
- name: production
envVarGroups:
- name: production-secrets
envVars:
- key: STRIPE_API_KEY
- key: SLACK_WEBHOOK
databases:
- name: app-db
plan: basic-1gb
previewPlan: basic-256mb
previewDiskSizeGB: 5
services:
- type: web
name: api
runtime: docker
plan: standard
previewPlan: starter
rootDir: apps/api
dockerfilePath: ./apps/api/Dockerfile
dockerContext: .
dockerCommand: node dist/server.js
healthCheckPath: /health
buildFilter:
paths:
- apps/api/**
- packages/shared-types/**
- pnpm-lock.yaml
ignoredPaths:
- apps/api/**/*.test.ts
scaling:
minInstances: 2
maxInstances: 10
targetCPUPercent: 70
envVars:
- key: DATABASE_URL
fromDatabase:
name: app-db
property: connectionString
- key: REDIS_URL
fromService:
name: cache
type: keyvalue
property: connectionString
- key: AUTH_URL
fromService:
name: auth
type: pserv
property: hostport
- key: JWT_SECRET
generateValue: true
- fromGroup: shared-config
- fromGroup: production-secrets
- type: pserv
name: auth
runtime: node
plan: starter
rootDir: apps/auth
buildCommand: pnpm install && pnpm --filter auth build
startCommand: pnpm --filter auth start
buildFilter:
paths:
- apps/auth/**
- packages/shared-types/**
- pnpm-lock.yaml
envVars:
- key: DATABASE_URL
fromDatabase:
name: app-db
property: connectionString
- key: API_SECRET
generateValue: true
- fromGroup: shared-config
- type: keyvalue
name: cache
plan: starter
maxmemoryPolicy: allkeys-lru
ipAllowList: []
- type: worker
name: media-processor
runtime: node
plan: starter
rootDir: apps/media
buildCommand: pnpm install && pnpm --filter media build
startCommand: pnpm --filter media start
disk:
name: media-cache
mountPath: /var/data/media
sizeGB: 20
previews:
generation: off
envVars:
- key: DATABASE_URL
fromDatabase:
name: app-db
property: connectionString
- fromGroup: shared-config
- type: cron
name: nightly-cleanup
runtime: image
schedule: "0 3 * * *"
image:
url: ghcr.io/acme/cleanup:v2.1.0
creds:
fromRegistryCreds:
name: ghcr
envVars:
- key: DATABASE_URL
fromDatabase:
name: app-db
property: connectionString
- fromGroup: shared-config
- name: staging
envVarGroups:
- name: staging-secrets
envVars:
- key: STRIPE_API_KEY
- key: SLACK_WEBHOOK
databases:
- name: app-db
plan: basic-256mb
services:
- type: web
name: api
runtime: docker
plan: starter
rootDir: apps/api
dockerfilePath: ./apps/api/Dockerfile
dockerContext: .
dockerCommand: node dist/server.js
healthCheckPath: /health
envVars:
- key: DATABASE_URL
fromDatabase:
name: app-db
property: connectionString
- fromGroup: shared-config
- fromGroup: staging-secrets

That’s the whole stack: a Docker-built web service, a Node private service for auth, a Key Value cache, a disk-backed worker for media, and a cron that runs a prebuilt image - all in production, with a slimmer staging mirror, and previews on for everything except the worker.

What each pattern brings

StepPatternWhere it shows up
02Projects + environmentsprojects → environments → production / staging
03Env groups, scopedshared-config (project) + production-secrets (env)
04All six wiring primitivesfromDatabase, fromService (kv + pserv), fromGroup, generateValue, plain value
05Previews + per-service overridespreviews.generation: automatic, worker opts out
06rootDir + buildFilterPer-service paths including packages/** + lockfile
07Disk + autoscalingDisk on worker, autoscaling on web
08runtime: docker and runtime: imageWeb (docker) + cron (image)

Most real Blueprints land somewhere on this spectrum - usually a third of these features. Composability is the point: each pattern is independent, and they don’t fight each other.

The CI workflow that keeps it honest

The Blueprint above is exactly the kind of file you don’t want to merge unvalidated. Drop this into .github/workflows/render-blueprint.yml and every PR that touches it runs the same validation you ran locally:

.github/workflows/render-blueprint.yml
name: Validate render.yaml
on:
pull_request:
paths:
- "render.yaml"
- ".github/workflows/render-blueprint.yml"
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install the Render CLI
run: |
curl -fsSL https://raw.githubusercontent.com/render-oss/cli/main/bin/install.sh | sh
echo "$HOME/.render/bin" >> "$GITHUB_PATH"
- name: Validate Blueprint
run: render blueprints validate

The paths: filter keeps the job idle on PRs that don’t touch the Blueprint, so it costs almost nothing on a busy repo. GitLab and Bitbucket pipelines follow the same shape - install the CLI, run render blueprints validate, fail the job on a non-zero exit.

Where to go next

The patterns in this cookbook give you the shape of a production-grade Blueprint. The next milestones are operational:

  • Deploy a Blueprint end-to-end - the Deploy SF Pulse on Render tutorial walks the deploy flow with a real example app.
  • Author Blueprints with AI assistance - your AI coding tool already has the render-blueprints skill installed. Hand it the schema URL and it’ll generate, validate, and explain Blueprints inline.
  • Connect Render’s MCP server - point Claude, Cursor, or Codex at mcp.render.com and your AI tool can list services, fetch logs, and trigger deploys without leaving the editor.

What’s deliberately out of scope

This cookbook covered eight of the patterns most teams reach for. A few things you’ll bump into eventually but that aren’t here:

  • Immutable-fields-and-recreation patterns - the rules for which database/service fields can never be edited (e.g. databaseName, region, postgresMajorVersion) and the recipes for safely working around them.
  • End-to-end deploy walkthroughs - handled by the existing render-workflows, Deploy SF Pulse on Render, and Extend SF Pulse with Render Workflows tutorials.
  • Workflow-specific Blueprint quirks - runtime: workflow isn’t supported in render.yaml yet; create the Workflow service from the Render Dashboard.
A teammate adds a new service to the Blueprint. They're rushed and skip running `render blueprints validate` locally. The CI job in this step is configured. What's the worst-case outcome?

What you learned

  • A real Blueprint composes projects/environments, env groups, wiring primitives, previews, monorepo filters, disks, scaling, and Docker/image runtimes - all without fighting each other
  • Pair the Blueprint with a CI workflow that runs `render blueprints validate` on every PR that touches the file
  • When you're ready to deploy, hand off to the workflow-specific tutorials, the `render-deploy` skill, or the Render MCP server