KeyEnvKeyEnv

Render

Sync KeyEnv secrets to Render services.

Render Integration

Sync secrets from KeyEnv to your Render services.

Prerequisites

  • Render account with a deployed service
  • Render API key
  • KeyEnv service token with read access

Integration Scripts

The integrations/render/ directory contains ready-to-use sync scripts in Bash, TypeScript, and Python. These scripts use the Render API directly (no KeyEnv CLI required):

# Clone or copy from the repo
cd integrations/render

export KEYENV_TOKEN=your-keyenv-token
export RENDER_API_KEY=your-render-api-key
export RENDER_SERVICE_ID=srv-xxxxxxxxxxxxx

./sync-to-render.sh          # Bash
npx ts-node sync-to-render.ts  # TypeScript
python3 sync-to-render.py    # Python

By default the scripts merge KeyEnv secrets with existing Render env vars (KeyEnv takes precedence). Set REPLACE_ALL=true to replace all Render vars.

Quick Sync

For a one-off sync using the KeyEnv CLI:

#!/bin/bash
set -euo pipefail

export KEYENV_TOKEN=your-keyenv-token
export RENDER_API_KEY=your-render-api-key
RENDER_SERVICE_ID=srv-xxxxxxxxxxxxx

# Export and sync
secrets=$(keyenv export -p YOUR_PROJECT_ID -e production --format json)

echo "$secrets" | jq '[.secrets[] | {key: .key, value: .value}]' | \
  curl -s -X PUT "https://api.render.com/v1/services/$RENDER_SERVICE_ID/env-vars" \
    -H "Authorization: Bearer $RENDER_API_KEY" \
    -H "Content-Type: application/json" \
    -d @-

echo "Secrets synced to Render!"

Find Your Service ID

  1. Go to your Render Dashboard
  2. Click on your service
  3. The Service ID is in the URL: dashboard.render.com/web/srv-xxxxxxxxxxxxx

Or use the API:

curl -s "https://api.render.com/v1/services" \
  -H "Authorization: Bearer $RENDER_API_KEY" | \
  jq '.[] | {name: .service.name, id: .service.id}'

Sync Script

Create a reusable sync script:

#!/bin/bash
# sync-to-render.sh

set -euo pipefail

: "${KEYENV_TOKEN:?KEYENV_TOKEN is required}"
: "${RENDER_API_KEY:?RENDER_API_KEY is required}"

PROJECT_ID="${KEYENV_PROJECT:-YOUR_PROJECT_ID}"
ENVIRONMENT="${KEYENV_ENV:-production}"
SERVICE_ID="${RENDER_SERVICE_ID:-srv-xxxxxxxxxxxxx}"

echo "Syncing KeyEnv ($ENVIRONMENT) to Render ($SERVICE_ID)..."

# Export secrets from KeyEnv
secrets=$(keyenv export -p "$PROJECT_ID" -e "$ENVIRONMENT" --format json)

# Transform and sync to Render
echo "$secrets" | jq '[.secrets[] | {key: .key, value: .value}]' | \
  curl -s -X PUT "https://api.render.com/v1/services/$SERVICE_ID/env-vars" \
    -H "Authorization: Bearer $RENDER_API_KEY" \
    -H "Content-Type: application/json" \
    -d @-

echo "Done! Render will automatically redeploy."

CI/CD Integration

GitHub Actions

name: Deploy to Render

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install KeyEnv CLI
        run: curl -fsSL https://keyenv.dev/install.sh | bash

      - name: Sync secrets to Render
        run: |
          export PATH="$HOME/.keyenv/bin:$PATH"

          secrets=$(keyenv export -p ${{ vars.KEYENV_PROJECT }} -e production --format json)

          echo "$secrets" | jq '[.secrets[] | {key: .key, value: .value}]' | \
            curl -s -X PUT "https://api.render.com/v1/services/${{ vars.RENDER_SERVICE_ID }}/env-vars" \
              -H "Authorization: Bearer ${{ secrets.RENDER_API_KEY }}" \
              -H "Content-Type: application/json" \
              -d @-
        env:
          KEYENV_TOKEN: ${{ secrets.KEYENV_TOKEN }}

      - name: Trigger deploy
        run: |
          curl -X POST "https://api.render.com/v1/services/${{ vars.RENDER_SERVICE_ID }}/deploys" \
            -H "Authorization: Bearer ${{ secrets.RENDER_API_KEY }}"

Multiple Services

Sync to multiple Render services:

#!/bin/bash
# sync-all-services.sh

declare -A SERVICES=(
  ["web"]="srv-web123"
  ["api"]="srv-api456"
  ["worker"]="srv-worker789"
)

for name in "${!SERVICES[@]}"; do
  service_id="${SERVICES[$name]}"
  echo "Syncing to $name ($service_id)..."

  secrets=$(keyenv export -p YOUR_PROJECT_ID -e production --format json)

  echo "$secrets" | jq '[.secrets[] | {key: .key, value: .value}]' | \
    curl -s -X PUT "https://api.render.com/v1/services/$service_id/env-vars" \
      -H "Authorization: Bearer $RENDER_API_KEY" \
      -H "Content-Type: application/json" \
      -d @-
done

Environment Groups

Render supports environment groups for sharing secrets across services. Sync to a group:

# Get environment group ID
curl -s "https://api.render.com/v1/env-groups" \
  -H "Authorization: Bearer $RENDER_API_KEY" | jq '.'

# Sync to environment group
ENV_GROUP_ID="evg-xxxxxxxxxxxxx"
secrets=$(keyenv export -p YOUR_PROJECT_ID -e production --format json)

echo "$secrets" | jq '[.secrets[] | {key: .key, value: .value}]' | \
  curl -s -X PUT "https://api.render.com/v1/env-groups/$ENV_GROUP_ID/env-vars" \
    -H "Authorization: Bearer $RENDER_API_KEY" \
    -H "Content-Type: application/json" \
    -d @-

Selective Sync

Sync only specific secrets:

secrets=$(keyenv export -p YOUR_PROJECT_ID -e production --format json)

# Only sync secrets starting with "DB_" or "API_"
echo "$secrets" | \
  jq '[.secrets[] | select(.key | test("^(DB_|API_)")) | {key: .key, value: .value}]' | \
  curl -s -X PUT "https://api.render.com/v1/services/$SERVICE_ID/env-vars" \
    -H "Authorization: Bearer $RENDER_API_KEY" \
    -H "Content-Type: application/json" \
    -d @-

Verify Sync

Check current environment variables:

curl -s "https://api.render.com/v1/services/$SERVICE_ID/env-vars" \
  -H "Authorization: Bearer $RENDER_API_KEY" | \
  jq '.[] | {key: .envVar.key}'

render.yaml Configuration

For Blueprint-based deployments, non-sensitive config goes in render.yaml:

services:
  - type: web
    name: myapp
    env: node
    buildCommand: npm install && npm run build
    startCommand: npm start
    envVars:
      - key: NODE_ENV
        value: production
      - key: LOG_LEVEL
        value: info
      # Sensitive values synced from KeyEnv via API

Best Practices

  1. Use environment groups - Share common secrets across services
  2. Automate syncing - Run sync in CI/CD before deployments
  3. Don't mix methods - Either use render.yaml OR API sync, not both for the same keys
  4. Version control non-secrets - Put non-sensitive config in render.yaml

Troubleshooting

API Rate Limits

Render has API rate limits. If syncing many services:

for service_id in "${SERVICE_IDS[@]}"; do
  # ... sync ...
  sleep 1  # Add delay between requests
done

Service Not Redeploying

Trigger a manual deploy after syncing:

curl -X POST "https://api.render.com/v1/services/$SERVICE_ID/deploys" \
  -H "Authorization: Bearer $RENDER_API_KEY"

Permission Errors

Verify your API key has the right permissions:

curl -s "https://api.render.com/v1/owners" \
  -H "Authorization: Bearer $RENDER_API_KEY"

On this page