# Render

Sync KeyEnv secrets to Render services.

Source: https://keyenv.dev/docs/guides/render/

Sync secrets from KeyEnv to your Render services.

## Prerequisites

- Render account with a deployed service
- [Render API key](https://render.com/docs/api#getting-started)
- KeyEnv service token with read access

## Integration Scripts

The [`integrations/render/`](https://github.com/keyenv/keyenv/tree/main/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):

```bash
# 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:

```bash
#!/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:

```bash
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:

```bash
#!/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

```yaml
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:

```bash
#!/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:

```bash
# 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:

```bash
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:

```bash
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`:

```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:

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

### Service Not Redeploying

Trigger a manual deploy after syncing:

```bash
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:

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