@intentsolutionsio/supabase-pack 1.0.0 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +73 -47
- package/package.json +4 -4
- package/skills/supabase-advanced-troubleshooting/SKILL.md +404 -200
- package/skills/supabase-advanced-troubleshooting/references/errors.md +11 -0
- package/skills/supabase-advanced-troubleshooting/references/evidence-collection-framework.md +34 -0
- package/skills/supabase-advanced-troubleshooting/references/examples.md +11 -0
- package/skills/supabase-advanced-troubleshooting/references/rls-edge-functions-realtime.md +363 -0
- package/skills/supabase-advanced-troubleshooting/references/systematic-isolation.md +56 -0
- package/skills/supabase-advanced-troubleshooting/references/timing-analysis.md +35 -0
- package/skills/supabase-architecture-variants/SKILL.md +395 -216
- package/skills/supabase-architecture-variants/references/errors.md +11 -0
- package/skills/supabase-architecture-variants/references/examples.md +12 -0
- package/skills/supabase-architecture-variants/references/serverless-and-multi-tenant.md +251 -0
- package/skills/supabase-architecture-variants/references/variant-a-monolith-(simple).md +44 -0
- package/skills/supabase-architecture-variants/references/variant-b-service-layer-(moderate).md +72 -0
- package/skills/supabase-architecture-variants/references/variant-c-microservice-(complex).md +81 -0
- package/skills/supabase-auth-storage-realtime-core/SKILL.md +471 -37
- package/skills/supabase-ci-integration/SKILL.md +315 -67
- package/skills/supabase-ci-integration/references/errors.md +10 -0
- package/skills/supabase-ci-integration/references/examples.md +36 -0
- package/skills/supabase-ci-integration/references/implementation.md +54 -0
- package/skills/supabase-common-errors/SKILL.md +320 -62
- package/skills/supabase-common-errors/references/errors.md +53 -0
- package/skills/supabase-common-errors/references/examples.md +23 -0
- package/skills/supabase-cost-tuning/SKILL.md +365 -131
- package/skills/supabase-cost-tuning/references/cost-estimation.md +34 -0
- package/skills/supabase-cost-tuning/references/cost-reduction-strategies.md +40 -0
- package/skills/supabase-cost-tuning/references/errors.md +11 -0
- package/skills/supabase-cost-tuning/references/examples.md +15 -0
- package/skills/supabase-data-handling/SKILL.md +378 -145
- package/skills/supabase-data-handling/references/errors.md +11 -0
- package/skills/supabase-data-handling/references/examples.md +27 -0
- package/skills/supabase-data-handling/references/implementation.md +223 -0
- package/skills/supabase-data-handling/references/retention-and-backup.md +221 -0
- package/skills/supabase-debug-bundle/SKILL.md +267 -73
- package/skills/supabase-debug-bundle/references/errors.md +12 -0
- package/skills/supabase-debug-bundle/references/examples.md +24 -0
- package/skills/supabase-debug-bundle/references/implementation.md +54 -0
- package/skills/supabase-deploy-integration/SKILL.md +258 -147
- package/skills/supabase-deploy-integration/references/errors.md +11 -0
- package/skills/supabase-deploy-integration/references/examples.md +21 -0
- package/skills/supabase-deploy-integration/references/google-cloud-run.md +36 -0
- package/skills/supabase-deploy-integration/references/vercel-deployment.md +35 -0
- package/skills/supabase-enterprise-rbac/SKILL.md +327 -160
- package/skills/supabase-enterprise-rbac/references/api-scoping-and-enforcement.md +255 -0
- package/skills/supabase-enterprise-rbac/references/errors.md +11 -0
- package/skills/supabase-enterprise-rbac/references/examples.md +12 -0
- package/skills/supabase-enterprise-rbac/references/role-implementation.md +33 -0
- package/skills/supabase-enterprise-rbac/references/sso-integration.md +35 -0
- package/skills/supabase-hello-world/SKILL.md +160 -54
- package/skills/supabase-incident-runbook/SKILL.md +453 -131
- package/skills/supabase-incident-runbook/references/errors.md +11 -0
- package/skills/supabase-incident-runbook/references/examples.md +10 -0
- package/skills/supabase-incident-runbook/references/immediate-actions-by-error-type.md +41 -0
- package/skills/supabase-install-auth/SKILL.md +186 -50
- package/skills/supabase-install-auth/references/examples.md +102 -0
- package/skills/supabase-known-pitfalls/SKILL.md +411 -241
- package/skills/supabase-known-pitfalls/references/errors.md +11 -0
- package/skills/supabase-known-pitfalls/references/examples.md +12 -0
- package/skills/supabase-load-scale/SKILL.md +346 -217
- package/skills/supabase-load-scale/references/capacity-planning.md +47 -0
- package/skills/supabase-load-scale/references/errors.md +11 -0
- package/skills/supabase-load-scale/references/examples.md +26 -0
- package/skills/supabase-load-scale/references/load-testing-with-k6.md +59 -0
- package/skills/supabase-load-scale/references/scaling-patterns.md +65 -0
- package/skills/supabase-load-scale/references/table-partitioning.md +263 -0
- package/skills/supabase-local-dev-loop/SKILL.md +272 -73
- package/skills/supabase-local-dev-loop/references/errors.md +11 -0
- package/skills/supabase-local-dev-loop/references/examples.md +21 -0
- package/skills/supabase-local-dev-loop/references/implementation.md +60 -0
- package/skills/supabase-migration-deep-dive/SKILL.md +338 -177
- package/skills/supabase-migration-deep-dive/references/backfill-versioning-rollback.md +258 -0
- package/skills/supabase-migration-deep-dive/references/errors.md +11 -0
- package/skills/supabase-migration-deep-dive/references/examples.md +12 -0
- package/skills/supabase-migration-deep-dive/references/implementation-plan.md +80 -0
- package/skills/supabase-migration-deep-dive/references/pre-migration-assessment.md +39 -0
- package/skills/supabase-multi-env-setup/SKILL.md +393 -152
- package/skills/supabase-multi-env-setup/references/configuration-structure.md +59 -0
- package/skills/supabase-multi-env-setup/references/errors.md +11 -0
- package/skills/supabase-multi-env-setup/references/examples.md +11 -0
- package/skills/supabase-observability/SKILL.md +318 -196
- package/skills/supabase-observability/references/alert-configuration.md +40 -0
- package/skills/supabase-observability/references/errors.md +11 -0
- package/skills/supabase-observability/references/examples.md +13 -0
- package/skills/supabase-observability/references/metrics-collection.md +65 -0
- package/skills/supabase-performance-tuning/SKILL.md +304 -160
- package/skills/supabase-performance-tuning/references/caching-strategy.md +49 -0
- package/skills/supabase-performance-tuning/references/errors.md +11 -0
- package/skills/supabase-performance-tuning/references/examples.md +13 -0
- package/skills/supabase-policy-guardrails/SKILL.md +248 -221
- package/skills/supabase-policy-guardrails/references/ci-cost-security.md +484 -0
- package/skills/supabase-policy-guardrails/references/errors.md +11 -0
- package/skills/supabase-policy-guardrails/references/eslint-rules.md +46 -0
- package/skills/supabase-policy-guardrails/references/examples.md +10 -0
- package/skills/supabase-prod-checklist/SKILL.md +474 -84
- package/skills/supabase-prod-checklist/references/errors.md +63 -0
- package/skills/supabase-prod-checklist/references/examples.md +153 -0
- package/skills/supabase-prod-checklist/references/implementation.md +113 -0
- package/skills/supabase-rate-limits/SKILL.md +311 -98
- package/skills/supabase-rate-limits/references/errors.md +11 -0
- package/skills/supabase-rate-limits/references/examples.md +46 -0
- package/skills/supabase-rate-limits/references/implementation.md +66 -0
- package/skills/supabase-reference-architecture/SKILL.md +249 -182
- package/skills/supabase-reference-architecture/references/errors.md +29 -0
- package/skills/supabase-reference-architecture/references/examples.md +116 -0
- package/skills/supabase-reference-architecture/references/key-components.md +244 -0
- package/skills/supabase-reference-architecture/references/project-structure.md +109 -0
- package/skills/supabase-reliability-patterns/SKILL.md +229 -234
- package/skills/supabase-reliability-patterns/references/circuit-breaker.md +36 -0
- package/skills/supabase-reliability-patterns/references/dead-letter-queue.md +48 -0
- package/skills/supabase-reliability-patterns/references/errors.md +11 -0
- package/skills/supabase-reliability-patterns/references/examples.md +11 -0
- package/skills/supabase-reliability-patterns/references/idempotency-keys.md +36 -0
- package/skills/supabase-reliability-patterns/references/offline-degradation-health-dualwrite.md +489 -0
- package/skills/supabase-schema-from-requirements/SKILL.md +373 -34
- package/skills/supabase-sdk-patterns/SKILL.md +388 -99
- package/skills/supabase-sdk-patterns/references/errors.md +11 -0
- package/skills/supabase-sdk-patterns/references/examples.md +45 -0
- package/skills/supabase-sdk-patterns/references/implementation.md +67 -0
- package/skills/supabase-security-basics/SKILL.md +282 -102
- package/skills/supabase-security-basics/references/errors.md +10 -0
- package/skills/supabase-security-basics/references/examples.md +70 -0
- package/skills/supabase-security-basics/references/implementation.md +39 -0
- package/skills/supabase-upgrade-migration/SKILL.md +248 -66
- package/skills/supabase-upgrade-migration/references/errors.md +10 -0
- package/skills/supabase-upgrade-migration/references/examples.md +51 -0
- package/skills/supabase-upgrade-migration/references/implementation.md +29 -0
- package/skills/supabase-webhooks-events/SKILL.md +412 -138
- package/skills/supabase-webhooks-events/references/errors.md +55 -0
- package/skills/supabase-webhooks-events/references/event-handler-pattern.md +106 -0
- package/skills/supabase-webhooks-events/references/examples.md +133 -0
- package/skills/supabase-webhooks-events/references/signature-verification.md +165 -0
|
@@ -1,222 +1,463 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: supabase-multi-env-setup
|
|
3
|
-
description:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
description: 'Configure Supabase across development, staging, and production with
|
|
4
|
+
separate projects,
|
|
5
|
+
|
|
6
|
+
environment-specific secrets, and safe migration promotion.
|
|
7
|
+
|
|
8
|
+
Use when setting up multi-environment deployments, isolating dev from prod data,
|
|
9
|
+
|
|
10
|
+
configuring per-environment Supabase projects, or promoting migrations through environments.
|
|
11
|
+
|
|
12
|
+
Trigger: "supabase environments", "supabase staging", "supabase dev prod",
|
|
13
|
+
|
|
14
|
+
"supabase multi-project", "supabase env config", "database branching".
|
|
15
|
+
|
|
16
|
+
'
|
|
17
|
+
allowed-tools: Read, Write, Edit, Bash(npx supabase:*), Bash(supabase:*), Bash(vercel:*),
|
|
18
|
+
Grep, Glob
|
|
10
19
|
version: 1.0.0
|
|
11
20
|
license: MIT
|
|
12
21
|
author: Jeremy Longshore <jeremy@intentsolutions.io>
|
|
22
|
+
tags:
|
|
23
|
+
- saas
|
|
24
|
+
- supabase
|
|
25
|
+
- deployment
|
|
26
|
+
- environments
|
|
27
|
+
- multi-env
|
|
28
|
+
- devops
|
|
29
|
+
compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
|
|
13
30
|
---
|
|
14
|
-
|
|
15
31
|
# Supabase Multi-Environment Setup
|
|
16
32
|
|
|
17
33
|
## Overview
|
|
18
|
-
|
|
34
|
+
|
|
35
|
+
Production Supabase deployments require separate projects per environment — each with its own URL, API keys, database, and RLS policies. This skill configures a three-tier environment architecture (local dev, staging, production) with safe migration promotion via `supabase db push`, environment-aware `createClient` initialization, database branching for preview deployments, and CI/CD pipelines that prevent accidental cross-environment operations.
|
|
36
|
+
|
|
37
|
+
**When to use:** Setting up a new project with multiple environments, migrating from a single-project setup to multi-env, adding staging to an existing dev/prod split, or configuring preview environments with database branching.
|
|
19
38
|
|
|
20
39
|
## Prerequisites
|
|
21
|
-
- Separate Supabase accounts or API keys per environment
|
|
22
|
-
- Secret management solution (Vault, AWS Secrets Manager, etc.)
|
|
23
|
-
- CI/CD pipeline with environment variables
|
|
24
|
-
- Environment detection in application
|
|
25
40
|
|
|
26
|
-
|
|
41
|
+
- Three separate Supabase projects created at [supabase.com/dashboard](https://supabase.com/dashboard) (dev, staging, production)
|
|
42
|
+
- Supabase CLI installed: `npm install -g supabase` or `npx supabase --version`
|
|
43
|
+
- `@supabase/supabase-js` v2+ installed in your project
|
|
44
|
+
- Node.js 18+ with framework that supports `.env` files (Next.js, Nuxt, SvelteKit, etc.)
|
|
45
|
+
- A secret management solution for CI (GitHub Actions Secrets, Vercel env vars, etc.)
|
|
46
|
+
|
|
47
|
+
## Instructions
|
|
48
|
+
|
|
49
|
+
### Step 1: Environment Files and Project Layout
|
|
27
50
|
|
|
28
|
-
|
|
29
|
-
|-------------|---------|----------|------|
|
|
30
|
-
| Development | Local dev | Test keys | Sandbox |
|
|
31
|
-
| Staging | Pre-prod validation | Staging keys | Test data |
|
|
32
|
-
| Production | Live traffic | Production keys | Real data |
|
|
51
|
+
Create one Supabase CLI project with shared migrations and per-environment credential files. Each `.env.*` file points to a different Supabase project.
|
|
33
52
|
|
|
34
|
-
|
|
53
|
+
**Project structure:**
|
|
35
54
|
|
|
36
55
|
```
|
|
37
|
-
|
|
56
|
+
my-app/
|
|
38
57
|
├── supabase/
|
|
39
|
-
│ ├──
|
|
40
|
-
│ ├──
|
|
41
|
-
│
|
|
42
|
-
│
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"timeout": 30000,
|
|
49
|
-
"retries": 3,
|
|
50
|
-
"cache": {
|
|
51
|
-
"enabled": true,
|
|
52
|
-
"ttlSeconds": 60
|
|
53
|
-
}
|
|
54
|
-
}
|
|
58
|
+
│ ├── config.toml # Local CLI config
|
|
59
|
+
│ ├── migrations/ # Shared migrations (all envs use the same schema)
|
|
60
|
+
│ │ └── 20260101000000_initial.sql
|
|
61
|
+
│ ├── seed.sql # Dev-only seed data (runs on db reset only)
|
|
62
|
+
│ └── functions/ # Edge Functions (deployed per env)
|
|
63
|
+
├── .env.local # Local dev → supabase start
|
|
64
|
+
├── .env.staging # Staging project credentials
|
|
65
|
+
├── .env.production # Production project credentials
|
|
66
|
+
└── .gitignore # Must include .env.staging, .env.production
|
|
55
67
|
```
|
|
56
68
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
**Environment files:**
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# .env.local — local development (safe defaults from supabase start)
|
|
73
|
+
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
|
|
74
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0
|
|
75
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU
|
|
76
|
+
DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
|
|
77
|
+
SUPABASE_ENV=local
|
|
78
|
+
|
|
79
|
+
# .env.staging — staging project
|
|
80
|
+
NEXT_PUBLIC_SUPABASE_URL=https://<staging-ref>.supabase.co
|
|
81
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...staging-anon-key
|
|
82
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJ...staging-service-key
|
|
83
|
+
DATABASE_URL=postgres://postgres.<staging-ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres
|
|
84
|
+
SUPABASE_ENV=staging
|
|
85
|
+
|
|
86
|
+
# .env.production — production project (NEVER commit this file)
|
|
87
|
+
NEXT_PUBLIC_SUPABASE_URL=https://<prod-ref>.supabase.co
|
|
88
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...prod-anon-key
|
|
89
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJ...prod-service-key
|
|
90
|
+
DATABASE_URL=postgres://postgres.<prod-ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres
|
|
91
|
+
SUPABASE_ENV=production
|
|
67
92
|
```
|
|
68
93
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
94
|
+
**Critical `.gitignore` entries:**
|
|
95
|
+
|
|
96
|
+
```gitignore
|
|
97
|
+
.env.staging
|
|
98
|
+
.env.production
|
|
99
|
+
# .env.local is safe to commit (contains only local dev keys)
|
|
76
100
|
```
|
|
77
101
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
102
|
+
**Link each environment to the CLI:**
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
# Local development
|
|
106
|
+
npx supabase start
|
|
107
|
+
|
|
108
|
+
# Link staging (stores ref in supabase/.temp/project-ref)
|
|
109
|
+
npx supabase link --project-ref <staging-ref>
|
|
110
|
+
|
|
111
|
+
# Link production (re-links, overwriting staging ref)
|
|
112
|
+
npx supabase link --project-ref <prod-ref>
|
|
86
113
|
```
|
|
87
114
|
|
|
88
|
-
|
|
115
|
+
> **Note:** The CLI can only link one project at a time. Switch between environments by re-running `supabase link` with the target project ref before any `db push` or `functions deploy` operation.
|
|
116
|
+
|
|
117
|
+
### Step 2: Environment-Aware Client and Safeguards
|
|
118
|
+
|
|
119
|
+
Build a `createClient` wrapper that selects the correct URL and keys based on the active environment, plus production safeguards that block destructive operations.
|
|
120
|
+
|
|
121
|
+
**Environment detection (`lib/env.ts`):**
|
|
89
122
|
|
|
90
123
|
```typescript
|
|
91
|
-
|
|
92
|
-
import baseConfig from '../../config/supabase/base.json';
|
|
124
|
+
export type Environment = 'local' | 'staging' | 'production';
|
|
93
125
|
|
|
94
|
-
|
|
126
|
+
export function getEnvironment(): Environment {
|
|
127
|
+
// Explicit env var takes priority
|
|
128
|
+
const explicit = process.env.SUPABASE_ENV;
|
|
129
|
+
if (explicit === 'local' || explicit === 'staging' || explicit === 'production') {
|
|
130
|
+
return explicit;
|
|
131
|
+
}
|
|
95
132
|
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
: 'development';
|
|
133
|
+
// Fallback: detect from URL
|
|
134
|
+
const url = process.env.NEXT_PUBLIC_SUPABASE_URL ?? '';
|
|
135
|
+
if (url.includes('127.0.0.1') || url.includes('localhost')) return 'local';
|
|
136
|
+
if (url.includes('staging')) return 'staging';
|
|
137
|
+
return 'production';
|
|
102
138
|
}
|
|
103
139
|
|
|
104
|
-
export function
|
|
105
|
-
|
|
106
|
-
|
|
140
|
+
export function isProduction(): boolean {
|
|
141
|
+
return getEnvironment() === 'production';
|
|
142
|
+
}
|
|
107
143
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
144
|
+
export function requireNonProduction(operation: string): void {
|
|
145
|
+
if (isProduction()) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`[BLOCKED] "${operation}" is not allowed in production. ` +
|
|
148
|
+
`Current SUPABASE_ENV=${process.env.SUPABASE_ENV}`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
113
151
|
}
|
|
114
152
|
```
|
|
115
153
|
|
|
116
|
-
|
|
154
|
+
**Supabase client factory (`lib/supabase.ts`):**
|
|
117
155
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
156
|
+
```typescript
|
|
157
|
+
import { createClient, type SupabaseClient } from '@supabase/supabase-js';
|
|
158
|
+
import type { Database } from './database.types';
|
|
159
|
+
import { getEnvironment } from './env';
|
|
160
|
+
|
|
161
|
+
// Browser client (uses anon key, respects RLS)
|
|
162
|
+
export function createBrowserClient(): SupabaseClient<Database> {
|
|
163
|
+
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
|
164
|
+
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
|
165
|
+
|
|
166
|
+
return createClient<Database>(supabaseUrl, supabaseAnonKey, {
|
|
167
|
+
auth: {
|
|
168
|
+
autoRefreshToken: true,
|
|
169
|
+
persistSession: true,
|
|
170
|
+
},
|
|
171
|
+
global: {
|
|
172
|
+
headers: { 'x-environment': getEnvironment() },
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Server client (uses service role key, bypasses RLS)
|
|
178
|
+
export function createServerClient(): SupabaseClient<Database> {
|
|
179
|
+
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
|
180
|
+
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
|
181
|
+
|
|
182
|
+
return createClient<Database>(supabaseUrl, serviceRoleKey, {
|
|
183
|
+
auth: {
|
|
184
|
+
autoRefreshToken: false,
|
|
185
|
+
persistSession: false,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
122
189
|
```
|
|
123
190
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
191
|
+
**Production safeguards:**
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { requireNonProduction } from './env';
|
|
195
|
+
import { createServerClient } from './supabase';
|
|
196
|
+
|
|
197
|
+
// Seed data — only runs in local/staging
|
|
198
|
+
export async function seedTestData(): Promise<void> {
|
|
199
|
+
requireNonProduction('seedTestData');
|
|
200
|
+
const supabase = createServerClient();
|
|
201
|
+
await supabase.from('test_users').insert([
|
|
202
|
+
{ email: 'test@example.com', role: 'admin' },
|
|
203
|
+
{ email: 'user@example.com', role: 'member' },
|
|
204
|
+
]);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Destructive reset — only runs in local
|
|
208
|
+
export async function resetDatabase(): Promise<void> {
|
|
209
|
+
requireNonProduction('resetDatabase');
|
|
210
|
+
const supabase = createServerClient();
|
|
211
|
+
await supabase.rpc('truncate_all_tables');
|
|
212
|
+
}
|
|
128
213
|
```
|
|
129
214
|
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
# AWS Secrets Manager
|
|
133
|
-
aws secretsmanager get-secret-value --secret-id supabase/production/api-key
|
|
215
|
+
**Environment-specific RLS policies:**
|
|
134
216
|
|
|
135
|
-
|
|
136
|
-
|
|
217
|
+
```sql
|
|
218
|
+
-- supabase/migrations/20260115000000_env_rls.sql
|
|
219
|
+
-- Allow broader access in staging for QA testing
|
|
220
|
+
CREATE POLICY "staging_read_all" ON public.profiles
|
|
221
|
+
FOR SELECT
|
|
222
|
+
USING (
|
|
223
|
+
current_setting('app.environment', true) = 'staging'
|
|
224
|
+
OR auth.uid() = id
|
|
225
|
+
);
|
|
137
226
|
|
|
138
|
-
|
|
139
|
-
|
|
227
|
+
-- Set environment in each request via the x-environment header
|
|
228
|
+
-- or via a Postgres config parameter in your connection string
|
|
140
229
|
```
|
|
141
230
|
|
|
142
|
-
|
|
231
|
+
### Step 3: Migration Promotion and Database Branching
|
|
143
232
|
|
|
144
|
-
|
|
145
|
-
// Prevent production operations in non-prod
|
|
146
|
-
function guardProductionOperation(operation: string): void {
|
|
147
|
-
const config = getSupabaseConfig();
|
|
233
|
+
Promote migrations through environments (local -> staging -> production) and use database branching for preview deployments.
|
|
148
234
|
|
|
149
|
-
|
|
150
|
-
console.warn(`[supabase] ${operation} blocked in ${config.environment}`);
|
|
151
|
-
throw new Error(`${operation} only allowed in production`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
235
|
+
**Migration promotion workflow:**
|
|
154
236
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
237
|
+
```text
|
|
238
|
+
# 1. Create migration locally
|
|
239
|
+
npx supabase migration new add_profiles_table
|
|
240
|
+
# Edit: supabase/migrations/20260120000000_add_profiles_table.sql
|
|
241
|
+
|
|
242
|
+
# 2. Test locally with full reset
|
|
243
|
+
npx supabase db reset # Applies all migrations + seed.sql
|
|
244
|
+
npx supabase test db # Run pgTAP tests if configured
|
|
245
|
+
|
|
246
|
+
# 3. Push to staging
|
|
247
|
+
npx supabase link --project-ref <staging-ref>
|
|
248
|
+
npx supabase db push # Applies only new migrations
|
|
249
|
+
# Run integration tests against staging URL
|
|
250
|
+
|
|
251
|
+
# 4. Push to production (after staging verification)
|
|
252
|
+
npx supabase link --project-ref <prod-ref>
|
|
253
|
+
npx supabase db push # Same migrations, production database
|
|
254
|
+
# Verify with health check endpoint
|
|
255
|
+
|
|
256
|
+
# 5. Generate types from the canonical source
|
|
257
|
+
npx supabase gen types typescript --local > lib/database.types.ts
|
|
258
|
+
# Or from linked project:
|
|
259
|
+
# npx supabase gen types typescript --linked > lib/database.types.ts
|
|
160
260
|
```
|
|
161
261
|
|
|
162
|
-
|
|
262
|
+
**Database branching for preview environments:**
|
|
163
263
|
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
264
|
+
```text
|
|
265
|
+
# Create a branch for a feature (requires Supabase Pro plan)
|
|
266
|
+
npx supabase branches create feature-user-profiles \
|
|
267
|
+
--project-ref <staging-ref>
|
|
268
|
+
|
|
269
|
+
# Each branch gets its own:
|
|
270
|
+
# - Database with current migrations applied
|
|
271
|
+
# - Unique API URL and keys
|
|
272
|
+
# - Isolated storage buckets
|
|
273
|
+
|
|
274
|
+
# List active branches
|
|
275
|
+
npx supabase branches list --project-ref <staging-ref>
|
|
276
|
+
|
|
277
|
+
# Connect preview deployment to the branch
|
|
278
|
+
# In your CI (e.g., Vercel preview deploys):
|
|
279
|
+
NEXT_PUBLIC_SUPABASE_URL=https://<branch-ref>.supabase.co
|
|
280
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=<branch-anon-key>
|
|
281
|
+
|
|
282
|
+
# Delete branch after merge
|
|
283
|
+
npx supabase branches delete feature-user-profiles \
|
|
284
|
+
--project-ref <staging-ref>
|
|
179
285
|
```
|
|
180
286
|
|
|
181
|
-
|
|
287
|
+
**CI/CD per-environment deployment (`.github/workflows/deploy.yml`):**
|
|
182
288
|
|
|
183
|
-
|
|
184
|
-
|
|
289
|
+
```yaml
|
|
290
|
+
name: Deploy Supabase
|
|
291
|
+
on:
|
|
292
|
+
push:
|
|
293
|
+
branches: [develop, main]
|
|
294
|
+
|
|
295
|
+
jobs:
|
|
296
|
+
deploy-staging:
|
|
297
|
+
if: github.ref == 'refs/heads/develop'
|
|
298
|
+
runs-on: ubuntu-latest
|
|
299
|
+
steps:
|
|
300
|
+
- uses: actions/checkout@v4
|
|
301
|
+
- uses: supabase/setup-cli@v1
|
|
302
|
+
with:
|
|
303
|
+
version: latest
|
|
304
|
+
- name: Push migrations to staging
|
|
305
|
+
run: |
|
|
306
|
+
npx supabase link --project-ref ${{ secrets.STAGING_PROJECT_REF }}
|
|
307
|
+
npx supabase db push
|
|
308
|
+
env:
|
|
309
|
+
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
|
|
310
|
+
SUPABASE_DB_PASSWORD: ${{ secrets.STAGING_DB_PASSWORD }}
|
|
311
|
+
- name: Deploy Edge Functions
|
|
312
|
+
run: npx supabase functions deploy --project-ref ${{ secrets.STAGING_PROJECT_REF }}
|
|
313
|
+
env:
|
|
314
|
+
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
|
|
315
|
+
|
|
316
|
+
deploy-production:
|
|
317
|
+
if: github.ref == 'refs/heads/main'
|
|
318
|
+
runs-on: ubuntu-latest
|
|
319
|
+
environment: production # Requires approval in GitHub
|
|
320
|
+
steps:
|
|
321
|
+
- uses: actions/checkout@v4
|
|
322
|
+
- uses: supabase/setup-cli@v1
|
|
323
|
+
with:
|
|
324
|
+
version: latest
|
|
325
|
+
- name: Push migrations to production
|
|
326
|
+
run: |
|
|
327
|
+
npx supabase link --project-ref ${{ secrets.PROD_PROJECT_REF }}
|
|
328
|
+
npx supabase db push
|
|
329
|
+
env:
|
|
330
|
+
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
|
|
331
|
+
SUPABASE_DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }}
|
|
332
|
+
- name: Deploy Edge Functions
|
|
333
|
+
run: npx supabase functions deploy --project-ref ${{ secrets.PROD_PROJECT_REF }}
|
|
334
|
+
env:
|
|
335
|
+
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
|
|
336
|
+
```
|
|
185
337
|
|
|
186
|
-
|
|
187
|
-
Add logic to detect and load environment-specific config.
|
|
338
|
+
**Environment-specific seed data:**
|
|
188
339
|
|
|
189
|
-
|
|
190
|
-
|
|
340
|
+
```sql
|
|
341
|
+
-- supabase/seed.sql (runs ONLY on `supabase db reset`, never in production)
|
|
342
|
+
INSERT INTO public.profiles (id, email, role) VALUES
|
|
343
|
+
('00000000-0000-0000-0000-000000000001', 'admin@test.local', 'admin'),
|
|
344
|
+
('00000000-0000-0000-0000-000000000002', 'user@test.local', 'member');
|
|
191
345
|
|
|
192
|
-
|
|
193
|
-
|
|
346
|
+
-- Insert test data for local development
|
|
347
|
+
INSERT INTO public.projects (name, owner_id) VALUES
|
|
348
|
+
('Test Project', '00000000-0000-0000-0000-000000000001');
|
|
349
|
+
```
|
|
194
350
|
|
|
195
351
|
## Output
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
-
|
|
352
|
+
|
|
353
|
+
After completing this skill, you will have:
|
|
354
|
+
|
|
355
|
+
- **Three isolated Supabase projects** — each environment has its own URL, API keys, database, and storage
|
|
356
|
+
- **Environment-specific `.env` files** — `.env.local`, `.env.staging`, `.env.production` with correct credentials
|
|
357
|
+
- **Environment-aware `createClient`** — browser and server clients auto-configured from env vars with `x-environment` header tracking
|
|
358
|
+
- **Production safeguards** — `requireNonProduction()` guard blocks destructive operations outside local/staging
|
|
359
|
+
- **Migration promotion pipeline** — `supabase db push` promotes schema changes local -> staging -> production
|
|
360
|
+
- **Database branching** — preview environments get isolated database branches (Pro plan)
|
|
361
|
+
- **CI/CD workflows** — GitHub Actions deploys migrations and Edge Functions per environment with approval gates for production
|
|
362
|
+
- **Generated TypeScript types** — `database.types.ts` generated from local or linked project schema
|
|
200
363
|
|
|
201
364
|
## Error Handling
|
|
202
|
-
|
|
365
|
+
|
|
366
|
+
| Error | Cause | Solution |
|
|
203
367
|
|-------|-------|----------|
|
|
204
|
-
|
|
|
205
|
-
|
|
|
206
|
-
|
|
|
207
|
-
|
|
|
368
|
+
| `Cannot find project ref` | CLI not linked to a project | Run `npx supabase link --project-ref <ref>` before `db push` |
|
|
369
|
+
| `Migration has already been applied` | Re-running an existing migration | Check `supabase_migrations.schema_migrations` table; migrations are idempotent by ref |
|
|
370
|
+
| `Permission denied for schema public` | Wrong database password | Verify `SUPABASE_DB_PASSWORD` matches the project's database password in dashboard |
|
|
371
|
+
| `Seed data appeared in production` | Ran `supabase db reset` on prod | `seed.sql` only runs on `db reset` — never reset production; use `db push` instead |
|
|
372
|
+
| `Wrong environment keys in client` | `.env` file mismatch | Check `SUPABASE_ENV` var and verify URL matches expected project ref |
|
|
373
|
+
| `Branch creation failed` | Free plan or branching not enabled | Database branching requires Supabase Pro plan; enable in project settings |
|
|
374
|
+
| `Migration drift between envs` | Skipped staging promotion | Always promote through staging first; compare with `supabase migration list` per project |
|
|
375
|
+
| `Type generation mismatch` | Types generated from wrong env | Regenerate from local (`--local`) or re-link to the canonical environment |
|
|
208
376
|
|
|
209
377
|
## Examples
|
|
210
378
|
|
|
211
|
-
|
|
379
|
+
**Example 1 — Quick three-env bootstrap:**
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
# Initialize Supabase in existing project
|
|
383
|
+
npx supabase init
|
|
384
|
+
|
|
385
|
+
# Start local
|
|
386
|
+
npx supabase start
|
|
387
|
+
# Copy output keys to .env.local
|
|
388
|
+
|
|
389
|
+
# Create staging + production projects in dashboard
|
|
390
|
+
# Copy their URLs and keys to .env.staging / .env.production
|
|
391
|
+
|
|
392
|
+
# Create first migration
|
|
393
|
+
npx supabase migration new create_users
|
|
394
|
+
# Edit the migration, then:
|
|
395
|
+
npx supabase db reset # Test locally
|
|
396
|
+
|
|
397
|
+
# Promote to staging
|
|
398
|
+
npx supabase link --project-ref abcdefghijklmnop
|
|
399
|
+
npx supabase db push
|
|
400
|
+
|
|
401
|
+
# Promote to production
|
|
402
|
+
npx supabase link --project-ref qrstuvwxyz123456
|
|
403
|
+
npx supabase db push
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**Example 2 — Next.js middleware for environment validation:**
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
// middleware.ts
|
|
410
|
+
import { NextResponse } from 'next/server';
|
|
411
|
+
import type { NextRequest } from 'next/server';
|
|
412
|
+
|
|
413
|
+
export function middleware(request: NextRequest) {
|
|
414
|
+
const response = NextResponse.next();
|
|
415
|
+
|
|
416
|
+
// Add environment header for observability
|
|
417
|
+
const env = process.env.SUPABASE_ENV ?? 'unknown';
|
|
418
|
+
response.headers.set('x-supabase-env', env);
|
|
419
|
+
|
|
420
|
+
// Block admin routes in production unless authenticated
|
|
421
|
+
if (env === 'production' && request.nextUrl.pathname.startsWith('/admin/seed')) {
|
|
422
|
+
return NextResponse.json({ error: 'Not available in production' }, { status: 403 });
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return response;
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Example 3 — Verify environment before destructive operations:**
|
|
430
|
+
|
|
212
431
|
```typescript
|
|
213
|
-
|
|
214
|
-
|
|
432
|
+
import { getEnvironment, requireNonProduction } from '@/lib/env';
|
|
433
|
+
|
|
434
|
+
async function adminResetHandler(req: Request) {
|
|
435
|
+
const env = getEnvironment();
|
|
436
|
+
console.log(`[admin-reset] Running in ${env} environment`);
|
|
437
|
+
|
|
438
|
+
requireNonProduction('admin-reset');
|
|
439
|
+
|
|
440
|
+
// Safe to proceed — we're in local or staging
|
|
441
|
+
const { error } = await supabase.rpc('reset_test_data');
|
|
442
|
+
if (error) throw error;
|
|
443
|
+
|
|
444
|
+
return Response.json({ status: 'reset complete', environment: env });
|
|
445
|
+
}
|
|
215
446
|
```
|
|
216
447
|
|
|
217
448
|
## Resources
|
|
218
|
-
|
|
219
|
-
- [
|
|
449
|
+
|
|
450
|
+
- [Managing Environments — Supabase Docs](https://supabase.com/docs/guides/deployment/managing-environments)
|
|
451
|
+
- [Database Migrations — Supabase Docs](https://supabase.com/docs/guides/deployment/database-migrations)
|
|
452
|
+
- [Database Branching — Supabase Docs](https://supabase.com/docs/guides/deployment/branching)
|
|
453
|
+
- [Supabase CLI Reference](https://supabase.com/docs/reference/cli/introduction)
|
|
454
|
+
- [createClient — @supabase/supabase-js](https://supabase.com/docs/reference/javascript/initializing)
|
|
455
|
+
- [GitHub Actions with Supabase](https://supabase.com/docs/guides/deployment/managing-environments#using-github-actions)
|
|
456
|
+
- [12-Factor App — Config](https://12factor.net/config)
|
|
220
457
|
|
|
221
458
|
## Next Steps
|
|
222
|
-
|
|
459
|
+
|
|
460
|
+
- For authentication patterns across environments, see `supabase-auth-storage-realtime-core`
|
|
461
|
+
- For RLS policy testing and validation, see `supabase-policy-guardrails`
|
|
462
|
+
- For local development workflow optimization, see `supabase-local-dev-loop`
|
|
463
|
+
- For monitoring and observability across environments, see `supabase-observability`
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Configuration Structure
|
|
2
|
+
|
|
3
|
+
## Configuration Structure
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
config/
|
|
7
|
+
├── supabase/
|
|
8
|
+
│ ├── base.json # Shared config
|
|
9
|
+
│ ├── development.json # Dev overrides
|
|
10
|
+
│ ├── staging.json # Staging overrides
|
|
11
|
+
│ └── production.json # Prod overrides
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### base.json
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"timeout": 30000,
|
|
19
|
+
"retries": 3,
|
|
20
|
+
"cache": {
|
|
21
|
+
"enabled": true,
|
|
22
|
+
"ttlSeconds": 60
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### development.json
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"apiKey": "${SUPABASE_API_KEY}",
|
|
32
|
+
"baseUrl": "https://api-sandbox.supabase.com",
|
|
33
|
+
"debug": true,
|
|
34
|
+
"cache": {
|
|
35
|
+
"enabled": false
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### staging.json
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"apiKey": "${SUPABASE_API_KEY_STAGING}",
|
|
45
|
+
"baseUrl": "https://api-staging.supabase.com",
|
|
46
|
+
"debug": false
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### production.json
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"apiKey": "${SUPABASE_API_KEY_PROD}",
|
|
55
|
+
"baseUrl": "https://api.supabase.com",
|
|
56
|
+
"debug": false,
|
|
57
|
+
"retries": 5
|
|
58
|
+
}
|
|
59
|
+
```
|