$npx -y skills add digitalocean-labs/do-app-platform-skills --skill postgresConfigure DigitalOcean Managed Postgres with bindable variables or schema isolation. Use when setting up databases, creating users, managing permissions, configuring multi-tenant schemas, or troubleshooting database connectivity on App Platform.
| 1 | # Postgres Skill |
| 2 | |
| 3 | Configure DigitalOcean Managed Postgres databases with proper security isolation and production-ready defaults. |
| 4 | |
| 5 | ## Quick Decision |
| 6 | |
| 7 | ``` |
| 8 | Need multiple isolated schemas in one database? |
| 9 | ├── YES → Path B (Schema Isolation) |
| 10 | └── NO → Path A (Bindable Variables) ✅ RECOMMENDED |
| 11 | ``` |
| 12 | |
| 13 | --- |
| 14 | |
| 15 | ## Path A: Bindable Variables (Recommended) |
| 16 | |
| 17 | Use when: Single app per database, standard CRUD applications. |
| 18 | |
| 19 | ### Quick Start |
| 20 | |
| 21 | ```bash |
| 22 | # 1. Create cluster + user via doctl (DO stores password internally) |
| 23 | doctl databases create my-app-db --engine pg --region nyc3 --size db-s-1vcpu-2gb |
| 24 | CLUSTER_ID=$(doctl databases list --format ID,Name --no-header | grep my-app-db | awk '{print $1}') |
| 25 | doctl databases db create $CLUSTER_ID myappdb |
| 26 | doctl databases user create $CLUSTER_ID myappuser |
| 27 | |
| 28 | # 2. Grant permissions (REQUIRED - users have no access by default!) |
| 29 | # Run: scripts/grant_permissions.sql as doadmin |
| 30 | |
| 31 | # 3. Reference in app spec |
| 32 | ``` |
| 33 | |
| 34 | ```yaml |
| 35 | # .do/app.yaml |
| 36 | databases: |
| 37 | - name: db |
| 38 | engine: PG |
| 39 | production: true |
| 40 | cluster_name: my-app-db |
| 41 | db_name: myappdb |
| 42 | db_user: myappuser |
| 43 | |
| 44 | services: |
| 45 | - name: api |
| 46 | envs: |
| 47 | - key: DATABASE_URL |
| 48 | scope: RUN_TIME |
| 49 | value: ${db.DATABASE_URL} |
| 50 | ``` |
| 51 | |
| 52 | **Full guide**: See [path-a-bindable-vars.md](reference/path-a-bindable-vars.md) |
| 53 | |
| 54 | --- |
| 55 | |
| 56 | ## Path B: Schema Isolation |
| 57 | |
| 58 | Use when: Multi-tenant SaaS, multiple apps sharing one cluster, schema-level isolation needed. |
| 59 | |
| 60 | ### Quick Start |
| 61 | |
| 62 | ```bash |
| 63 | # Hands-free setup (requires gh CLI) |
| 64 | ./scripts/secure_setup.sh \ |
| 65 | --admin-url "$ADMIN_URL" \ |
| 66 | --app-name myapp \ |
| 67 | --schema myapp \ |
| 68 | --repo owner/repo |
| 69 | ``` |
| 70 | |
| 71 | Password flows directly to GitHub Secrets — never displayed. |
| 72 | |
| 73 | **Full guide**: See [path-b-schema-isolation.md](reference/path-b-schema-isolation.md) |
| 74 | |
| 75 | --- |
| 76 | |
| 77 | ## Available Bindable Variables |
| 78 | |
| 79 | | Variable | Example | |
| 80 | |----------|---------| |
| 81 | | `${db.DATABASE_URL}` | `postgresql://user:pass@host:25060/db?sslmode=require` | |
| 82 | | `${db.HOSTNAME}` | `my-db-do-user-123.db.ondigitalocean.com` | |
| 83 | | `${db.PORT}` | `25060` | |
| 84 | | `${db.USERNAME}` | `myappuser` | |
| 85 | | `${db.PASSWORD}` | (auto-populated) | |
| 86 | | `${db.DATABASE}` | `myappdb` | |
| 87 | | `${db.CA_CERT}` | (certificate content) | |
| 88 | |
| 89 | --- |
| 90 | |
| 91 | ## Scripts |
| 92 | |
| 93 | | Script | Purpose | |
| 94 | |--------|---------| |
| 95 | | `scripts/secure_setup.sh` | Hands-free Path B setup with GitHub Secrets | |
| 96 | | `scripts/create_schema_user.py` | Create isolated schema + user | |
| 97 | | `scripts/list_schemas_users.py` | Audit existing schemas/users | |
| 98 | | `scripts/generate_connection_string.py` | Build connection strings | |
| 99 | |
| 100 | --- |
| 101 | |
| 102 | ## Reference Files |
| 103 | |
| 104 | - **[path-a-bindable-vars.md](reference/path-a-bindable-vars.md)** — Full Path A workflow, connection pools, multi-app setup |
| 105 | - **[path-b-schema-isolation.md](reference/path-b-schema-isolation.md)** — Full Path B workflow, multi-tenant patterns |
| 106 | - **[orm-configurations.md](reference/orm-configurations.md)** — Prisma, SQLAlchemy, Drizzle, TypeORM configs |
| 107 | - **[database-migrations.md](reference/database-migrations.md)** — Alembic, Prisma Migrate, Drizzle Migrate |
| 108 | - **[doctl-reference.md](reference/doctl-reference.md)** — All `doctl databases` commands |
| 109 | - **[troubleshooting.md](reference/troubleshooting.md)** — Common errors and fixes |
| 110 | - **[bundled-scripts.md](reference/bundled-scripts.md)** — Script usage documentation |
| 111 | |
| 112 | --- |
| 113 | |
| 114 | ## Common Issues (Quick Fixes) |
| 115 | |
| 116 | | Error | Fix | |
| 117 | |-------|-----| |
| 118 | | "permission denied for schema" | Run permission SQL as doadmin | |
| 119 | | "relation does not exist" | Check `search_path` or use schema-qualified names | |
| 120 | | "too many connections" | Create connection pool via doctl | |
| 121 | | "SSL connection required" | Add `?sslmode=require` to connection string | |
| 122 | | Bindable vars not populated | Verify `production: true` and names match exactly | |
| 123 | |
| 124 | **Full troubleshooting**: See [troubleshooting.md](reference/troubleshooting.md) |
| 125 | |
| 126 | --- |
| 127 | |
| 128 | ## Integration with Other Skills |
| 129 | |
| 130 | - **→ designer**: Add database block to app spec |
| 131 | - **→ deployment**: GitHub Actions workflow with DATABASE_URL secret |
| 132 | - **→ devcontainers**: Local Postgres with prod parity |
| 133 | - **→ troubleshooting**: Debug container for connectivity testing |