@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.
Files changed (133) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +73 -47
  3. package/package.json +4 -4
  4. package/skills/supabase-advanced-troubleshooting/SKILL.md +404 -200
  5. package/skills/supabase-advanced-troubleshooting/references/errors.md +11 -0
  6. package/skills/supabase-advanced-troubleshooting/references/evidence-collection-framework.md +34 -0
  7. package/skills/supabase-advanced-troubleshooting/references/examples.md +11 -0
  8. package/skills/supabase-advanced-troubleshooting/references/rls-edge-functions-realtime.md +363 -0
  9. package/skills/supabase-advanced-troubleshooting/references/systematic-isolation.md +56 -0
  10. package/skills/supabase-advanced-troubleshooting/references/timing-analysis.md +35 -0
  11. package/skills/supabase-architecture-variants/SKILL.md +395 -216
  12. package/skills/supabase-architecture-variants/references/errors.md +11 -0
  13. package/skills/supabase-architecture-variants/references/examples.md +12 -0
  14. package/skills/supabase-architecture-variants/references/serverless-and-multi-tenant.md +251 -0
  15. package/skills/supabase-architecture-variants/references/variant-a-monolith-(simple).md +44 -0
  16. package/skills/supabase-architecture-variants/references/variant-b-service-layer-(moderate).md +72 -0
  17. package/skills/supabase-architecture-variants/references/variant-c-microservice-(complex).md +81 -0
  18. package/skills/supabase-auth-storage-realtime-core/SKILL.md +471 -37
  19. package/skills/supabase-ci-integration/SKILL.md +315 -67
  20. package/skills/supabase-ci-integration/references/errors.md +10 -0
  21. package/skills/supabase-ci-integration/references/examples.md +36 -0
  22. package/skills/supabase-ci-integration/references/implementation.md +54 -0
  23. package/skills/supabase-common-errors/SKILL.md +320 -62
  24. package/skills/supabase-common-errors/references/errors.md +53 -0
  25. package/skills/supabase-common-errors/references/examples.md +23 -0
  26. package/skills/supabase-cost-tuning/SKILL.md +365 -131
  27. package/skills/supabase-cost-tuning/references/cost-estimation.md +34 -0
  28. package/skills/supabase-cost-tuning/references/cost-reduction-strategies.md +40 -0
  29. package/skills/supabase-cost-tuning/references/errors.md +11 -0
  30. package/skills/supabase-cost-tuning/references/examples.md +15 -0
  31. package/skills/supabase-data-handling/SKILL.md +378 -145
  32. package/skills/supabase-data-handling/references/errors.md +11 -0
  33. package/skills/supabase-data-handling/references/examples.md +27 -0
  34. package/skills/supabase-data-handling/references/implementation.md +223 -0
  35. package/skills/supabase-data-handling/references/retention-and-backup.md +221 -0
  36. package/skills/supabase-debug-bundle/SKILL.md +267 -73
  37. package/skills/supabase-debug-bundle/references/errors.md +12 -0
  38. package/skills/supabase-debug-bundle/references/examples.md +24 -0
  39. package/skills/supabase-debug-bundle/references/implementation.md +54 -0
  40. package/skills/supabase-deploy-integration/SKILL.md +258 -147
  41. package/skills/supabase-deploy-integration/references/errors.md +11 -0
  42. package/skills/supabase-deploy-integration/references/examples.md +21 -0
  43. package/skills/supabase-deploy-integration/references/google-cloud-run.md +36 -0
  44. package/skills/supabase-deploy-integration/references/vercel-deployment.md +35 -0
  45. package/skills/supabase-enterprise-rbac/SKILL.md +327 -160
  46. package/skills/supabase-enterprise-rbac/references/api-scoping-and-enforcement.md +255 -0
  47. package/skills/supabase-enterprise-rbac/references/errors.md +11 -0
  48. package/skills/supabase-enterprise-rbac/references/examples.md +12 -0
  49. package/skills/supabase-enterprise-rbac/references/role-implementation.md +33 -0
  50. package/skills/supabase-enterprise-rbac/references/sso-integration.md +35 -0
  51. package/skills/supabase-hello-world/SKILL.md +160 -54
  52. package/skills/supabase-incident-runbook/SKILL.md +453 -131
  53. package/skills/supabase-incident-runbook/references/errors.md +11 -0
  54. package/skills/supabase-incident-runbook/references/examples.md +10 -0
  55. package/skills/supabase-incident-runbook/references/immediate-actions-by-error-type.md +41 -0
  56. package/skills/supabase-install-auth/SKILL.md +186 -50
  57. package/skills/supabase-install-auth/references/examples.md +102 -0
  58. package/skills/supabase-known-pitfalls/SKILL.md +411 -241
  59. package/skills/supabase-known-pitfalls/references/errors.md +11 -0
  60. package/skills/supabase-known-pitfalls/references/examples.md +12 -0
  61. package/skills/supabase-load-scale/SKILL.md +346 -217
  62. package/skills/supabase-load-scale/references/capacity-planning.md +47 -0
  63. package/skills/supabase-load-scale/references/errors.md +11 -0
  64. package/skills/supabase-load-scale/references/examples.md +26 -0
  65. package/skills/supabase-load-scale/references/load-testing-with-k6.md +59 -0
  66. package/skills/supabase-load-scale/references/scaling-patterns.md +65 -0
  67. package/skills/supabase-load-scale/references/table-partitioning.md +263 -0
  68. package/skills/supabase-local-dev-loop/SKILL.md +272 -73
  69. package/skills/supabase-local-dev-loop/references/errors.md +11 -0
  70. package/skills/supabase-local-dev-loop/references/examples.md +21 -0
  71. package/skills/supabase-local-dev-loop/references/implementation.md +60 -0
  72. package/skills/supabase-migration-deep-dive/SKILL.md +338 -177
  73. package/skills/supabase-migration-deep-dive/references/backfill-versioning-rollback.md +258 -0
  74. package/skills/supabase-migration-deep-dive/references/errors.md +11 -0
  75. package/skills/supabase-migration-deep-dive/references/examples.md +12 -0
  76. package/skills/supabase-migration-deep-dive/references/implementation-plan.md +80 -0
  77. package/skills/supabase-migration-deep-dive/references/pre-migration-assessment.md +39 -0
  78. package/skills/supabase-multi-env-setup/SKILL.md +393 -152
  79. package/skills/supabase-multi-env-setup/references/configuration-structure.md +59 -0
  80. package/skills/supabase-multi-env-setup/references/errors.md +11 -0
  81. package/skills/supabase-multi-env-setup/references/examples.md +11 -0
  82. package/skills/supabase-observability/SKILL.md +318 -196
  83. package/skills/supabase-observability/references/alert-configuration.md +40 -0
  84. package/skills/supabase-observability/references/errors.md +11 -0
  85. package/skills/supabase-observability/references/examples.md +13 -0
  86. package/skills/supabase-observability/references/metrics-collection.md +65 -0
  87. package/skills/supabase-performance-tuning/SKILL.md +304 -160
  88. package/skills/supabase-performance-tuning/references/caching-strategy.md +49 -0
  89. package/skills/supabase-performance-tuning/references/errors.md +11 -0
  90. package/skills/supabase-performance-tuning/references/examples.md +13 -0
  91. package/skills/supabase-policy-guardrails/SKILL.md +248 -221
  92. package/skills/supabase-policy-guardrails/references/ci-cost-security.md +484 -0
  93. package/skills/supabase-policy-guardrails/references/errors.md +11 -0
  94. package/skills/supabase-policy-guardrails/references/eslint-rules.md +46 -0
  95. package/skills/supabase-policy-guardrails/references/examples.md +10 -0
  96. package/skills/supabase-prod-checklist/SKILL.md +474 -84
  97. package/skills/supabase-prod-checklist/references/errors.md +63 -0
  98. package/skills/supabase-prod-checklist/references/examples.md +153 -0
  99. package/skills/supabase-prod-checklist/references/implementation.md +113 -0
  100. package/skills/supabase-rate-limits/SKILL.md +311 -98
  101. package/skills/supabase-rate-limits/references/errors.md +11 -0
  102. package/skills/supabase-rate-limits/references/examples.md +46 -0
  103. package/skills/supabase-rate-limits/references/implementation.md +66 -0
  104. package/skills/supabase-reference-architecture/SKILL.md +249 -182
  105. package/skills/supabase-reference-architecture/references/errors.md +29 -0
  106. package/skills/supabase-reference-architecture/references/examples.md +116 -0
  107. package/skills/supabase-reference-architecture/references/key-components.md +244 -0
  108. package/skills/supabase-reference-architecture/references/project-structure.md +109 -0
  109. package/skills/supabase-reliability-patterns/SKILL.md +229 -234
  110. package/skills/supabase-reliability-patterns/references/circuit-breaker.md +36 -0
  111. package/skills/supabase-reliability-patterns/references/dead-letter-queue.md +48 -0
  112. package/skills/supabase-reliability-patterns/references/errors.md +11 -0
  113. package/skills/supabase-reliability-patterns/references/examples.md +11 -0
  114. package/skills/supabase-reliability-patterns/references/idempotency-keys.md +36 -0
  115. package/skills/supabase-reliability-patterns/references/offline-degradation-health-dualwrite.md +489 -0
  116. package/skills/supabase-schema-from-requirements/SKILL.md +373 -34
  117. package/skills/supabase-sdk-patterns/SKILL.md +388 -99
  118. package/skills/supabase-sdk-patterns/references/errors.md +11 -0
  119. package/skills/supabase-sdk-patterns/references/examples.md +45 -0
  120. package/skills/supabase-sdk-patterns/references/implementation.md +67 -0
  121. package/skills/supabase-security-basics/SKILL.md +282 -102
  122. package/skills/supabase-security-basics/references/errors.md +10 -0
  123. package/skills/supabase-security-basics/references/examples.md +70 -0
  124. package/skills/supabase-security-basics/references/implementation.md +39 -0
  125. package/skills/supabase-upgrade-migration/SKILL.md +248 -66
  126. package/skills/supabase-upgrade-migration/references/errors.md +10 -0
  127. package/skills/supabase-upgrade-migration/references/examples.md +51 -0
  128. package/skills/supabase-upgrade-migration/references/implementation.md +29 -0
  129. package/skills/supabase-webhooks-events/SKILL.md +412 -138
  130. package/skills/supabase-webhooks-events/references/errors.md +55 -0
  131. package/skills/supabase-webhooks-events/references/event-handler-pattern.md +106 -0
  132. package/skills/supabase-webhooks-events/references/examples.md +133 -0
  133. package/skills/supabase-webhooks-events/references/signature-verification.md +165 -0
@@ -0,0 +1,11 @@
1
+ # Error Handling Reference
2
+
3
+ | Issue | Cause | Solution |
4
+ |-------|-------|----------|
5
+ | Too many findings | Legacy codebase | Prioritize security first |
6
+ | Pattern not detected | Complex code | Manual review |
7
+ | False positive | Similar code | Whitelist exceptions |
8
+ | Fix breaks tests | Behavior change | Update tests |
9
+
10
+ ---
11
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
@@ -0,0 +1,12 @@
1
+ ## Examples
2
+
3
+ ### Quick Pitfall Scan
4
+
5
+ ```bash
6
+ # Check for common pitfalls
7
+ grep -r "sk_live_" --include="*.ts" src/ # Key leakage
8
+ grep -r "console.log" --include="*.ts" src/ # Potential PII logging
9
+ ```
10
+
11
+ ---
12
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
@@ -1,274 +1,403 @@
1
1
  ---
2
2
  name: supabase-load-scale
3
- description: |
4
- Implement Supabase load testing, auto-scaling, and capacity planning strategies.
5
- Use when running performance tests, configuring horizontal scaling,
6
- or planning capacity for Supabase integrations.
7
- Trigger with phrases like "supabase load test", "supabase scale",
8
- "supabase performance test", "supabase capacity", "supabase k6", "supabase benchmark".
9
- allowed-tools: Read, Write, Edit, Bash(k6:*), Bash(kubectl:*)
3
+ description: 'Scale Supabase projects for production load: read replicas, connection
4
+ pooling
5
+
6
+ tuning via Supavisor, compute size upgrades, CDN caching for Storage,
7
+
8
+ Edge Function regional deployment, and database table partitioning.
9
+
10
+ Use when preparing for traffic spikes, optimizing connection limits,
11
+
12
+ setting up read replicas for analytics queries, or partitioning large tables.
13
+
14
+ Trigger with phrases like "supabase scale", "supabase read replica",
15
+
16
+ "supabase connection pooling", "supabase compute upgrade",
17
+
18
+ "supabase CDN storage", "supabase edge function regions",
19
+
20
+ "supabase partitioning", "supavisor", "supabase pool mode".
21
+
22
+ '
23
+ allowed-tools: Read, Write, Edit, Bash(supabase:*), Bash(psql:*), Bash(curl:*), Grep
10
24
  version: 1.0.0
11
25
  license: MIT
12
26
  author: Jeremy Longshore <jeremy@intentsolutions.io>
27
+ tags:
28
+ - saas
29
+ - supabase
30
+ - scaling
31
+ - performance
32
+ - connection-pooling
33
+ - read-replicas
34
+ - partitioning
35
+ compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
13
36
  ---
14
-
15
37
  # Supabase Load & Scale
16
38
 
17
39
  ## Overview
18
- Load testing, scaling strategies, and capacity planning for Supabase integrations.
40
+
41
+ Supabase scaling operates at six layers: **read replicas** (offload analytics and reporting queries), **connection pooling** (Supavisor pgBouncer replacement with transaction/session modes), **compute upgrades** (vCPU/RAM tiers), **CDN for Storage** (cache public bucket assets at the edge), **Edge Function regions** (deploy functions closer to users), and **table partitioning** (split billion-row tables for query performance). This skill covers each layer with real `createClient` configuration, SQL, and CLI commands.
19
42
 
20
43
  ## Prerequisites
21
- - k6 load testing tool installed
22
- - Kubernetes cluster with HPA configured
23
- - Prometheus for metrics collection
24
- - Test environment API keys
25
-
26
- ## Load Testing with k6
27
-
28
- ### Basic Load Test
29
- ```javascript
30
- // supabase-load-test.js
31
- import http from 'k6/http';
32
- import { check, sleep } from 'k6';
33
-
34
- export const options = {
35
- stages: [
36
- { duration: '2m', target: 10 }, // Ramp up
37
- { duration: '5m', target: 10 }, // Steady state
38
- { duration: '2m', target: 50 }, // Ramp to peak
39
- { duration: '5m', target: 50 }, // Stress test
40
- { duration: '2m', target: 0 }, // Ramp down
41
- ],
42
- thresholds: {
43
- http_req_duration: ['p(95)<200'],
44
- http_req_failed: ['rate<0.01'],
45
- },
46
- };
47
-
48
- export default function () {
49
- const response = http.post(
50
- 'https://api.supabase.com/v1/resource',
51
- JSON.stringify({ test: true }),
52
- {
53
- headers: {
54
- 'Content-Type': 'application/json',
55
- 'Authorization': `Bearer ${__ENV.SUPABASE_API_KEY}`,
56
- },
57
- }
58
- );
59
44
 
60
- check(response, {
61
- 'status is 200': (r) => r.status === 200,
62
- 'latency < 200ms': (r) => r.timings.duration < 200,
63
- });
45
+ - Supabase project on a Pro plan or higher (read replicas require Pro+)
46
+ - `@supabase/supabase-js` v2+ installed
47
+ - `supabase` CLI installed and linked to your project
48
+ - Database access via `psql` or Supabase SQL Editor
49
+ - TypeScript project with generated database types
64
50
 
65
- sleep(1);
66
- }
51
+ ## Step 1 — Read Replicas and Connection Pooling
52
+
53
+ Read replicas let you route read-heavy queries (dashboards, reports, search) to replica databases while keeping writes on the primary. Supabase uses **Supavisor** (their pgBouncer replacement) for connection pooling with two modes: **transaction** (default, shares connections between requests) and **session** (holds a connection per client session, needed for prepared statements).
54
+
55
+ ### Configure the Read Replica Client
56
+
57
+ ```typescript
58
+ // lib/supabase.ts
59
+ import { createClient } from '@supabase/supabase-js'
60
+ import type { Database } from './database.types'
61
+
62
+ // Primary client — handles all writes and real-time subscriptions
63
+ export const supabase = createClient<Database>(
64
+ process.env.SUPABASE_URL!,
65
+ process.env.SUPABASE_ANON_KEY!
66
+ )
67
+
68
+ // Read replica client — use for analytics, dashboards, search
69
+ // The read replica URL is available in Dashboard > Settings > Database
70
+ export const supabaseReadOnly = createClient<Database>(
71
+ process.env.SUPABASE_READ_REPLICA_URL!, // e.g., https://<project-ref>-ro.supabase.co
72
+ process.env.SUPABASE_ANON_KEY!, // same anon key works for replicas
73
+ {
74
+ db: { schema: 'public' },
75
+ // Replicas may have slight lag (typically <100ms)
76
+ // Do NOT use for reads-after-writes in the same request
77
+ }
78
+ )
79
+
80
+ // Server-side admin client with connection pooling via Supavisor
81
+ // Use the pooled connection string (port 6543) instead of direct (port 5432)
82
+ export const supabaseAdmin = createClient<Database>(
83
+ process.env.SUPABASE_URL!,
84
+ process.env.SUPABASE_SERVICE_ROLE_KEY!,
85
+ {
86
+ auth: { autoRefreshToken: false, persistSession: false },
87
+ db: { schema: 'public' },
88
+ }
89
+ )
67
90
  ```
68
91
 
69
- ### Run Load Test
92
+ ### Direct Postgres Connections via Supavisor Pooling
93
+
70
94
  ```bash
71
- # Install k6
72
- brew install k6 # macOS
73
- # or: sudo apt install k6 # Linux
95
+ # Transaction mode (default, port 6543) — best for serverless/short-lived connections
96
+ # Shares connections across clients. Cannot use prepared statements.
97
+ psql "postgresql://postgres.[project-ref]:[password]@aws-0-us-east-1.pooler.supabase.com:6543/postgres"
74
98
 
75
- # Run test
76
- k6 run --env SUPABASE_API_KEY=${SUPABASE_API_KEY} supabase-load-test.js
99
+ # Session mode (port 5432 via pooler) — needed for prepared statements, LISTEN/NOTIFY
100
+ # One-to-one connection mapping per client.
101
+ psql "postgresql://postgres.[project-ref]:[password]@aws-0-us-east-1.pooler.supabase.com:5432/postgres"
77
102
 
78
- # Run with output to InfluxDB
79
- k6 run --out influxdb=http://localhost:8086/k6 supabase-load-test.js
103
+ # Direct connection (no pooling) — for migrations and admin tasks only
104
+ psql "postgresql://postgres:[password]@db.[project-ref].supabase.co:5432/postgres"
80
105
  ```
81
106
 
82
- ## Scaling Patterns
83
-
84
- ### Horizontal Scaling
85
- ```yaml
86
- # kubernetes HPA
87
- apiVersion: autoscaling/v2
88
- kind: HorizontalPodAutoscaler
89
- metadata:
90
- name: supabase-integration-hpa
91
- spec:
92
- scaleTargetRef:
93
- apiVersion: apps/v1
94
- kind: Deployment
95
- name: supabase-integration
96
- minReplicas: 2
97
- maxReplicas: 20
98
- metrics:
99
- - type: Resource
100
- resource:
101
- name: cpu
102
- target:
103
- type: Utilization
104
- averageUtilization: 70
105
- - type: Pods
106
- pods:
107
- metric:
108
- name: supabase_queue_depth
109
- target:
110
- type: AverageValue
111
- averageValue: 100
112
- ```
107
+ ### Route Queries to the Right Target
113
108
 
114
- ### Connection Pooling
115
109
  ```typescript
116
- import { Pool } from 'generic-pool';
117
-
118
- const supabasePool = Pool.create({
119
- create: async () => {
120
- return new SupabaseClient({
121
- apiKey: process.env.SUPABASE_API_KEY!,
122
- });
123
- },
124
- destroy: async (client) => {
125
- await client.close();
126
- },
127
- max: 20,
128
- min: 5,
129
- idleTimeoutMillis: 30000,
130
- });
131
-
132
- async function withSupabaseClient<T>(
133
- fn: (client: SupabaseClient) => Promise<T>
134
- ): Promise<T> {
135
- const client = await supabasePool.acquire();
136
- try {
137
- return await fn(client);
138
- } finally {
139
- supabasePool.release(client);
140
- }
110
+ // services/analytics.ts
111
+ import { supabaseReadOnly } from '../lib/supabase'
112
+
113
+ // Heavy analytics queries go to the read replica
114
+ export async function getDashboardMetrics(orgId: string) {
115
+ const { data, error } = await supabaseReadOnly
116
+ .from('events')
117
+ .select('event_type, count:id.count()')
118
+ .eq('org_id', orgId)
119
+ .gte('created_at', new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString())
120
+
121
+ if (error) throw new Error(`Dashboard query failed: ${error.message}`)
122
+ return data
123
+ }
124
+
125
+ // services/orders.ts
126
+ import { supabase } from '../lib/supabase'
127
+
128
+ // Writes always go to the primary
129
+ export async function createOrder(order: OrderInsert) {
130
+ const { data, error } = await supabase
131
+ .from('orders')
132
+ .insert(order)
133
+ .select('id, status, total, created_at')
134
+ .single()
135
+
136
+ if (error) throw new Error(`Order creation failed: ${error.message}`)
137
+ return data
141
138
  }
142
139
  ```
143
140
 
144
- ## Capacity Planning
141
+ ### Monitor Connection Pool Usage
142
+
143
+ ```sql
144
+ -- Check active connections by source (run in SQL Editor)
145
+ SELECT
146
+ usename,
147
+ application_name,
148
+ client_addr,
149
+ state,
150
+ count(*) AS connections
151
+ FROM pg_stat_activity
152
+ WHERE datname = 'postgres'
153
+ GROUP BY usename, application_name, client_addr, state
154
+ ORDER BY connections DESC;
155
+
156
+ -- Check connection limits for your compute tier
157
+ SHOW max_connections;
158
+ -- Micro: 60, Small: 90, Medium: 120, Large: 160, XL: 240, 2XL: 380, 4XL: 480
159
+ ```
160
+
161
+ ## Step 2 — Compute Upgrades, CDN for Storage, and Edge Function Regions
162
+
163
+ ### Compute Size Selection Guide
164
+
165
+ | Tier | vCPU | RAM | Max Connections | Best For |
166
+ |------|------|-----|----------------|----------|
167
+ | Micro (Free) | 2 shared | 1 GB | 60 | Development, prototypes |
168
+ | Small (Pro) | 2 dedicated | 2 GB | 90 | Low-traffic production |
169
+ | Medium | 2 dedicated | 4 GB | 120 | Growing apps, moderate traffic |
170
+ | Large | 4 dedicated | 8 GB | 160 | High-traffic, complex queries |
171
+ | XL | 8 dedicated | 16 GB | 240 | Large datasets, concurrent users |
172
+ | 2XL | 16 dedicated | 32 GB | 380 | Enterprise, heavy analytics |
173
+ | 4XL | 32 dedicated | 64 GB | 480 | Mission-critical, max throughput |
174
+
175
+ ```bash
176
+ # Upgrade compute via CLI (requires Pro plan)
177
+ supabase projects update --experimental --compute-size small # or medium, large, xl, 2xl, 4xl
178
+
179
+ # Check current compute size
180
+ supabase projects list
181
+ ```
182
+
183
+ ### CDN Caching for Storage Buckets
145
184
 
146
- ### Metrics to Monitor
147
- | Metric | Warning | Critical |
148
- |--------|---------|----------|
149
- | CPU Utilization | > 70% | > 85% |
150
- | Memory Usage | > 75% | > 90% |
151
- | Request Queue Depth | > 100 | > 500 |
152
- | Error Rate | > 1% | > 5% |
153
- | P95 Latency | > 500ms | > 2000ms |
185
+ Public buckets are automatically served through Supabase's CDN. Optimize cache behavior with proper headers and transforms.
154
186
 
155
- ### Capacity Calculation
156
187
  ```typescript
157
- interface CapacityEstimate {
158
- currentRPS: number;
159
- maxRPS: number;
160
- headroom: number;
161
- scaleRecommendation: string;
188
+ import { createClient } from '@supabase/supabase-js'
189
+
190
+ const supabase = createClient(
191
+ process.env.SUPABASE_URL!,
192
+ process.env.SUPABASE_ANON_KEY!
193
+ )
194
+
195
+ // Upload with cache-control headers for CDN optimization
196
+ async function uploadPublicAsset(
197
+ bucket: string,
198
+ path: string,
199
+ file: File
200
+ ) {
201
+ const { data, error } = await supabase.storage
202
+ .from(bucket)
203
+ .upload(path, file, {
204
+ cacheControl: '31536000', // 1 year cache for immutable assets
205
+ upsert: false, // prevent accidental overwrites
206
+ contentType: file.type,
207
+ })
208
+
209
+ if (error) throw new Error(`Upload failed: ${error.message}`)
210
+
211
+ // Get the CDN-cached public URL
212
+ const { data: { publicUrl } } = supabase.storage
213
+ .from(bucket)
214
+ .getPublicUrl(path, {
215
+ transform: {
216
+ width: 800, // Image transforms are cached at the CDN edge
217
+ quality: 80,
218
+ format: 'webp',
219
+ },
220
+ })
221
+
222
+ return { path: data.path, publicUrl }
162
223
  }
163
224
 
164
- function estimateSupabaseCapacity(
165
- metrics: SystemMetrics
166
- ): CapacityEstimate {
167
- const currentRPS = metrics.requestsPerSecond;
168
- const avgLatency = metrics.p50Latency;
169
- const cpuUtilization = metrics.cpuPercent;
170
-
171
- // Estimate max RPS based on current performance
172
- const maxRPS = currentRPS / (cpuUtilization / 100) * 0.7; // 70% target
173
- const headroom = ((maxRPS - currentRPS) / currentRPS) * 100;
174
-
175
- return {
176
- currentRPS,
177
- maxRPS: Math.floor(maxRPS),
178
- headroom: Math.round(headroom),
179
- scaleRecommendation: headroom < 30
180
- ? 'Scale up soon'
181
- : headroom < 50
182
- ? 'Monitor closely'
183
- : 'Adequate capacity',
184
- };
225
+ // Bust cache by uploading to a new path (content-addressed)
226
+ import { createHash } from 'crypto'
227
+
228
+ async function uploadVersionedAsset(bucket: string, file: Buffer, ext: string) {
229
+ const hash = createHash('sha256').update(file).digest('hex').slice(0, 12)
230
+ const path = `assets/${hash}.${ext}`
231
+
232
+ const { error } = await supabase.storage
233
+ .from(bucket)
234
+ .upload(path, file, {
235
+ cacheControl: '31536000',
236
+ upsert: false,
237
+ })
238
+
239
+ if (error && error.message !== 'The resource already exists') {
240
+ throw new Error(`Versioned upload failed: ${error.message}`)
241
+ }
242
+
243
+ return supabase.storage.from(bucket).getPublicUrl(path).data.publicUrl
185
244
  }
186
245
  ```
187
246
 
188
- ## Benchmark Results Template
189
-
190
- ```markdown
191
- ## Supabase Performance Benchmark
192
- **Date:** YYYY-MM-DD
193
- **Environment:** [staging/production]
194
- **SDK Version:** X.Y.Z
195
-
196
- ### Test Configuration
197
- - Duration: 10 minutes
198
- - Ramp: 10 → 100 → 10 VUs
199
- - Target endpoint: /v1/resource
200
-
201
- ### Results
202
- | Metric | Value |
203
- |--------|-------|
204
- | Total Requests | 50,000 |
205
- | Success Rate | 99.9% |
206
- | P50 Latency | 120ms |
207
- | P95 Latency | 350ms |
208
- | P99 Latency | 800ms |
209
- | Max RPS Achieved | 150 |
210
-
211
- ### Observations
212
- - [Key finding 1]
213
- - [Key finding 2]
214
-
215
- ### Recommendations
216
- - [Scaling recommendation]
217
- ```
247
+ ### Edge Function Regional Deployment
218
248
 
219
- ## Instructions
249
+ ```bash
250
+ # Deploy to a specific region (closer to your users)
251
+ supabase functions deploy my-function --region us-east-1
252
+ supabase functions deploy my-function --region eu-west-1
253
+ supabase functions deploy my-function --region ap-southeast-1
220
254
 
221
- ### Step 1: Create Load Test Script
222
- Write k6 test script with appropriate thresholds.
255
+ # List available regions
256
+ supabase functions list
223
257
 
224
- ### Step 2: Configure Auto-Scaling
225
- Set up HPA with CPU and custom metrics.
258
+ # Deploy all functions to a region
259
+ supabase functions deploy --region us-east-1
260
+ ```
226
261
 
227
- ### Step 3: Run Load Test
228
- Execute test and collect metrics.
262
+ ```typescript
263
+ // supabase/functions/geo-router/index.ts
264
+ // Edge Function that runs in the region closest to the user
265
+ import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
266
+
267
+ Deno.serve(async (req) => {
268
+ const supabase = createClient(
269
+ Deno.env.get('SUPABASE_URL')!,
270
+ Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
271
+ )
272
+
273
+ // Edge Functions automatically run in the nearest region
274
+ // Use this for latency-sensitive operations
275
+ const { data, error } = await supabase
276
+ .from('products')
277
+ .select('id, name, price')
278
+ .eq('region', req.headers.get('x-region') ?? 'us')
279
+ .limit(20)
280
+
281
+ if (error) {
282
+ return new Response(JSON.stringify({ error: error.message }), { status: 500 })
283
+ }
229
284
 
230
- ### Step 4: Analyze and Document
231
- Record results in benchmark template.
285
+ return new Response(JSON.stringify(data), {
286
+ headers: {
287
+ 'Content-Type': 'application/json',
288
+ 'Cache-Control': 'public, max-age=60', // CDN caches the response
289
+ },
290
+ })
291
+ })
292
+ ```
293
+
294
+ ## Step 3 — Database Table Partitioning
295
+
296
+ See [table partitioning patterns](references/table-partitioning.md) for range partitioning by date, automated partition creation via `pg_cron`, SDK query patterns with partition key filters, and partition drop for data retention.
232
297
 
233
298
  ## Output
234
- - Load test script created
235
- - HPA configured
236
- - Benchmark results documented
237
- - Capacity recommendations defined
299
+
300
+ - Read replica client configured for analytics/dashboard queries, primary for writes
301
+ - Connection pooling mode selected (transaction vs session) with correct port
302
+ - Compute tier matched to traffic requirements
303
+ - Storage uploads optimized with CDN cache headers and image transforms
304
+ - Edge Functions deployed to the region closest to users
305
+ - Large tables partitioned by date range with automated partition management
306
+ - Data retention policy via partition drops
238
307
 
239
308
  ## Error Handling
309
+
240
310
  | Issue | Cause | Solution |
241
311
  |-------|-------|----------|
242
- | k6 timeout | Rate limited | Reduce RPS |
243
- | HPA not scaling | Wrong metrics | Verify metric name |
244
- | Connection refused | Pool exhausted | Increase pool size |
245
- | Inconsistent results | Warm-up needed | Add ramp-up phase |
312
+ | `too many connections for role` | Exceeded Supavisor pool limit | Use transaction mode (port 6543), reduce idle connections, upgrade compute |
313
+ | Read replica returns stale data | Replication lag (typically <100ms) | Do not read-after-write on replica; use primary for consistency-critical reads |
314
+ | `no partition of relation "events" found for row` | Insert date outside any partition range | Create a DEFAULT partition or pre-create future partitions |
315
+ | Storage CDN returns old file | Cached at edge | Use content-addressed paths (`hash.ext`) or set shorter `cacheControl` |
316
+ | Edge Function cold start | First request to a region | Use `keep-alive` cron ping or accept ~200ms cold start |
317
+ | `prepared statement already exists` | Transaction mode doesn't support prepared statements | Switch to session mode (port 5432) or disable prepared statements in your ORM |
246
318
 
247
319
  ## Examples
248
320
 
249
- ### Quick k6 Test
321
+ ### Quick Connection Pool Check
322
+
250
323
  ```bash
251
- k6 run --vus 10 --duration 30s supabase-load-test.js
324
+ # Check how many connections are in use right now
325
+ psql "$DATABASE_URL" -c "SELECT count(*) AS active_connections FROM pg_stat_activity WHERE state = 'active';"
252
326
  ```
253
327
 
254
- ### Check Current Capacity
255
- ```typescript
256
- const metrics = await getSystemMetrics();
257
- const capacity = estimateSupabaseCapacity(metrics);
258
- console.log('Headroom:', capacity.headroom + '%');
259
- console.log('Recommendation:', capacity.scaleRecommendation);
328
+ ### Switch an Existing Table to Partitioned
329
+
330
+ ```sql
331
+ -- You cannot ALTER an existing table to be partitioned.
332
+ -- Instead: create partitioned table, migrate data, swap names.
333
+
334
+ -- 1. Create new partitioned table
335
+ CREATE TABLE public.events_partitioned (LIKE public.events INCLUDING ALL)
336
+ PARTITION BY RANGE (created_at);
337
+
338
+ -- 2. Create partitions for existing data range
339
+ CREATE TABLE public.events_p_2025_01 PARTITION OF public.events_partitioned
340
+ FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
341
+ -- ... more partitions
342
+
343
+ -- 3. Copy data (do this during low traffic)
344
+ INSERT INTO public.events_partitioned SELECT * FROM public.events;
345
+
346
+ -- 4. Swap tables in a transaction
347
+ BEGIN;
348
+ ALTER TABLE public.events RENAME TO events_old;
349
+ ALTER TABLE public.events_partitioned RENAME TO events;
350
+ COMMIT;
351
+
352
+ -- 5. Verify, then drop old table
353
+ DROP TABLE public.events_old;
260
354
  ```
261
355
 
262
- ### Scale HPA Manually
263
- ```bash
264
- kubectl scale deployment supabase-integration --replicas=5
265
- kubectl get hpa supabase-integration-hpa
356
+ ### Test Read Replica Lag
357
+
358
+ ```typescript
359
+ import { supabase, supabaseReadOnly } from '../lib/supabase'
360
+
361
+ async function measureReplicaLag() {
362
+ // Write to primary
363
+ const { data: written } = await supabase
364
+ .from('health_checks')
365
+ .insert({ timestamp: new Date().toISOString() })
366
+ .select('id, timestamp')
367
+ .single()
368
+
369
+ // Immediately read from replica
370
+ const start = Date.now()
371
+ let found = false
372
+
373
+ while (!found && Date.now() - start < 5000) {
374
+ const { data } = await supabaseReadOnly
375
+ .from('health_checks')
376
+ .select('id')
377
+ .eq('id', written!.id)
378
+ .maybeSingle()
379
+
380
+ if (data) {
381
+ found = true
382
+ console.log(`Replica lag: ${Date.now() - start}ms`)
383
+ } else {
384
+ await new Promise(r => setTimeout(r, 10))
385
+ }
386
+ }
387
+
388
+ if (!found) console.warn('Replica lag exceeds 5 seconds')
389
+ }
266
390
  ```
267
391
 
268
392
  ## Resources
269
- - [k6 Documentation](https://k6.io/docs/)
270
- - [Kubernetes HPA](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)
271
- - [Supabase Rate Limits](https://supabase.com/docs/rate-limits)
393
+
394
+ - [Supabase Read Replicas](https://supabase.com/docs/guides/platform/read-replicas)
395
+ - [Supabase Connection Pooling (Supavisor)](https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler)
396
+ - [Supabase Compute Add-ons](https://supabase.com/docs/guides/platform/compute-add-ons)
397
+ - [Supabase Storage CDN](https://supabase.com/docs/guides/storage/cdn/fundamentals)
398
+ - [Supabase Edge Functions](https://supabase.com/docs/guides/functions)
399
+ - [PostgreSQL Table Partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html)
272
400
 
273
401
  ## Next Steps
274
- For reliability patterns, see `supabase-reliability-patterns`.
402
+
403
+ For reliability patterns (circuit breakers, offline queues, graceful degradation), see `supabase-reliability-patterns`.