@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
@@ -1,201 +1,435 @@
1
1
  ---
2
2
  name: supabase-cost-tuning
3
- description: |
4
- Optimize Supabase costs through tier selection, sampling, and usage monitoring.
5
- Use when analyzing Supabase billing, reducing API costs,
6
- or implementing usage monitoring and budget alerts.
3
+ description: 'Optimize Supabase costs through plan selection, database tuning, storage
4
+ cleanup,
5
+
6
+ connection pooling, and Edge Function optimization.
7
+
8
+ Use when analyzing Supabase billing, reducing costs, right-sizing compute,
9
+
10
+ or implementing usage tracking and budget alerts.
11
+
7
12
  Trigger with phrases like "supabase cost", "supabase billing",
13
+
8
14
  "reduce supabase costs", "supabase pricing", "supabase expensive", "supabase budget".
9
- allowed-tools: Read, Grep
15
+
16
+ '
17
+ allowed-tools: Read, Write, Edit, Grep, Bash(supabase:*)
10
18
  version: 1.0.0
11
19
  license: MIT
12
20
  author: Jeremy Longshore <jeremy@intentsolutions.io>
21
+ tags:
22
+ - saas
23
+ - supabase
24
+ - cost-optimization
25
+ compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
13
26
  ---
14
-
15
27
  # Supabase Cost Tuning
16
28
 
17
29
  ## Overview
18
- Optimize Supabase costs through smart tier selection, sampling, and usage monitoring.
30
+
31
+ Reduce Supabase spend by auditing usage against plan limits, eliminating database and storage waste, and right-sizing compute resources. The three biggest levers: database optimization (vacuum, index cleanup, archival), storage lifecycle management (compress before upload, orphan cleanup), and connection pooling to reduce compute add-on requirements.
19
32
 
20
33
  ## Prerequisites
21
- - Access to Supabase billing dashboard
22
- - Understanding of current usage patterns
23
- - Database for usage tracking (optional)
24
- - Alerting system configured (optional)
25
34
 
26
- ## Pricing Tiers
35
+ - Supabase project with Dashboard access (Settings > Billing)
36
+ - `@supabase/supabase-js` installed: `npm install @supabase/supabase-js`
37
+ - Service role key for admin operations (storage audit, cleanup scripts)
38
+ - SQL editor access (Dashboard > SQL Editor or `psql` connection)
39
+
40
+ ## Pricing Reference
41
+
42
+ | Resource | Free Tier | Pro ($25/mo) | Team ($599/mo) |
43
+ |----------|-----------|--------------|----------------|
44
+ | Database | 500 MB | 8 GB included, $0.125/GB extra | 8 GB included |
45
+ | Storage | 1 GB | 100 GB included, $0.021/GB extra | 100 GB included |
46
+ | Bandwidth | 5 GB | 250 GB included, $0.09/GB extra | 250 GB included |
47
+ | Edge Functions | 500K invocations | 2M invocations, $2/million extra | 2M invocations |
48
+ | Realtime | 200 concurrent | 500 concurrent | 500 concurrent |
49
+ | Auth MAU | 50,000 | 100,000 | 100,000 |
50
+
51
+ **Compute add-ons** (Pro and above):
52
+
53
+ | Instance | vCPUs | RAM | Price |
54
+ |----------|-------|-----|-------|
55
+ | Micro | 2 | 1 GB | Included with Pro |
56
+ | Small | 2 | 2 GB | $25/mo |
57
+ | Medium | 2 | 4 GB | $50/mo |
58
+ | Large | 4 | 8 GB | $100/mo |
59
+ | XL | 8 | 16 GB | $200/mo |
60
+ | 2XL | 16 | 32 GB | $400/mo |
61
+
62
+ **Decision framework:** Read replicas ($25/mo each) beat scaling up when reads dominate and you need geographic distribution. Connection pooling (Supavisor, free) reduces compute pressure from idle connections.
63
+
64
+ ## Instructions
65
+
66
+ ### Step 1: Audit Current Usage and Identify Cost Drivers
67
+
68
+ Run these queries in the SQL Editor to understand where your database budget is going:
27
69
 
28
- | Tier | Monthly Cost | Included | Overage |
29
- |------|-------------|----------|---------|
30
- | Free | $0 | 500MB database, 1GB storage, 50K MAUs | N/A |
31
- | Pro | $25 | 8GB database, 100GB storage, 100K MAUs | $0.001/request |
32
- | Enterprise | Custom | Unlimited | Volume discounts |
70
+ ```sql
71
+ -- Total database size
72
+ select pg_size_pretty(pg_database_size(current_database())) as total_db_size;
73
+
74
+ -- Database size by table (find the biggest offenders)
75
+ select
76
+ relname as table_name,
77
+ pg_size_pretty(pg_total_relation_size(relid)) as total_size,
78
+ pg_size_pretty(pg_relation_size(relid)) as table_size,
79
+ pg_size_pretty(pg_total_relation_size(relid) - pg_relation_size(relid)) as index_size,
80
+ n_live_tup as row_count
81
+ from pg_stat_user_tables
82
+ order by pg_total_relation_size(relid) desc
83
+ limit 20;
84
+
85
+ -- Find unused indexes consuming space (zero scans since last stats reset)
86
+ select
87
+ schemaname || '.' || indexrelname as index_name,
88
+ pg_size_pretty(pg_relation_size(indexrelid)) as size,
89
+ idx_scan as scans_since_reset
90
+ from pg_stat_user_indexes
91
+ where idx_scan = 0
92
+ and schemaname = 'public'
93
+ order by pg_relation_size(indexrelid) desc
94
+ limit 10;
95
+
96
+ -- Check dead tuple bloat (high ratio means VACUUM is needed)
97
+ select
98
+ relname,
99
+ n_dead_tup,
100
+ n_live_tup,
101
+ round(n_dead_tup::numeric / greatest(n_live_tup, 1) * 100, 1) as dead_pct
102
+ from pg_stat_user_tables
103
+ where n_dead_tup > 1000
104
+ order by n_dead_tup desc;
105
+
106
+ -- Connection count (high count may indicate pooling issues)
107
+ select count(*) as active_connections,
108
+ max_conn as max_allowed
109
+ from pg_stat_activity,
110
+ (select setting::int as max_conn from pg_settings where name = 'max_connections') mc
111
+ group by max_conn;
112
+ ```
33
113
 
34
- ## Cost Estimation
114
+ Audit storage usage programmatically:
35
115
 
36
116
  ```typescript
37
- interface UsageEstimate {
38
- requestsPerMonth: number;
39
- tier: string;
40
- estimatedCost: number;
41
- recommendation?: string;
42
- }
117
+ import { createClient } from '@supabase/supabase-js'
43
118
 
44
- function estimateSupabaseCost(requestsPerMonth: number): UsageEstimate {
45
- if (requestsPerMonth <= 1000) {
46
- return { requestsPerMonth, tier: 'Free', estimatedCost: 0 };
47
- }
119
+ const supabaseAdmin = createClient(
120
+ process.env.SUPABASE_URL!,
121
+ process.env.SUPABASE_SERVICE_ROLE_KEY!
122
+ )
48
123
 
49
- if (requestsPerMonth <= 100000) {
50
- return { requestsPerMonth, tier: 'Pro', estimatedCost: 25 };
51
- }
124
+ // List storage usage per bucket
125
+ const { data: buckets } = await supabaseAdmin.storage.listBuckets()
52
126
 
53
- const proOverage = (requestsPerMonth - 100000) * 0.001;
54
- const proCost = 25 + proOverage;
55
-
56
- return {
57
- requestsPerMonth,
58
- tier: 'Pro (with overage)',
59
- estimatedCost: proCost,
60
- recommendation: proCost > 500
61
- ? 'Consider Enterprise tier for volume discounts'
62
- : undefined,
63
- };
127
+ for (const bucket of buckets ?? []) {
128
+ const { data: files } = await supabaseAdmin.storage
129
+ .from(bucket.name)
130
+ .list('', { limit: 1000 })
131
+
132
+ const totalSize = files?.reduce((sum, f) => sum + (f.metadata?.size || 0), 0) ?? 0
133
+ console.log(`${bucket.name}: ${(totalSize / 1024 / 1024).toFixed(1)} MB`)
64
134
  }
65
135
  ```
66
136
 
67
- ## Usage Monitoring
137
+ Check your current spend: **Dashboard > Settings > Billing** shows usage against plan limits with a breakdown by resource category.
68
138
 
69
- ```typescript
70
- class SupabaseUsageMonitor {
71
- private requestCount = 0;
72
- private bytesTransferred = 0;
73
- private alertThreshold: number;
139
+ ### Step 2: Optimize Database, Storage, and Bandwidth
74
140
 
75
- constructor(monthlyBudget: number) {
76
- this.alertThreshold = monthlyBudget * 0.8; // 80% warning
77
- }
141
+ **Database optimization — reclaim space and reduce bloat:**
78
142
 
79
- track(request: { bytes: number }) {
80
- this.requestCount++;
81
- this.bytesTransferred += request.bytes;
143
+ ```sql
144
+ -- Archive old data before deleting (preserve for compliance/analytics)
145
+ create table if not exists public.events_archive (like public.events including all);
82
146
 
83
- if (this.estimatedCost() > this.alertThreshold) {
84
- this.sendAlert('Approaching Supabase budget limit');
85
- }
86
- }
147
+ insert into public.events_archive
148
+ select * from public.events
149
+ where created_at < now() - interval '6 months';
87
150
 
88
- estimatedCost(): number {
89
- return estimateSupabaseCost(this.requestCount).estimatedCost;
90
- }
151
+ delete from public.events
152
+ where created_at < now() - interval '6 months';
91
153
 
92
- private sendAlert(message: string) {
93
- // Send to Slack, email, PagerDuty, etc.
94
- }
95
- }
154
+ -- Run VACUUM ANALYZE to reclaim space and update query planner stats
155
+ vacuum (verbose, analyze) public.events;
156
+
157
+ -- Drop confirmed-unused indexes (verify idx_scan = 0 from Step 1)
158
+ -- WARNING: always confirm the index is unused before dropping
159
+ drop index if exists idx_events_legacy_status;
160
+
161
+ -- Remove soft-deleted records past retention period
162
+ delete from public.orders
163
+ where deleted_at is not null
164
+ and deleted_at < now() - interval '90 days';
165
+
166
+ vacuum (analyze) public.orders;
96
167
  ```
97
168
 
98
- ## Cost Reduction Strategies
169
+ **Storage optimization compress before upload, clean orphans:**
99
170
 
100
- ### Step 1: Request Sampling
101
171
  ```typescript
102
- function shouldSample(samplingRate = 0.1): boolean {
103
- return Math.random() < samplingRate;
172
+ // Compress images before upload (reduces storage + bandwidth)
173
+ async function uploadCompressed(
174
+ bucket: string,
175
+ path: string,
176
+ file: File
177
+ ): Promise<string> {
178
+ // Use client-side compression before uploading
179
+ const compressed = await compressImage(file, { maxWidth: 1920, quality: 0.8 })
180
+
181
+ const { data, error } = await supabaseAdmin.storage
182
+ .from(bucket)
183
+ .upload(path, compressed, {
184
+ contentType: file.type,
185
+ upsert: true,
186
+ })
187
+
188
+ if (error) throw error
189
+ return data.path
104
190
  }
105
191
 
106
- // Use for non-critical telemetry
107
- if (shouldSample(0.1)) { // 10% sample
108
- await supabaseClient.trackEvent(event);
192
+ // Clean orphaned files older than 30 days
193
+ async function cleanOrphanedUploads() {
194
+ const cutoff = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString()
195
+
196
+ const { data: orphans } = await supabaseAdmin
197
+ .from('storage.objects')
198
+ .select('name, created_at')
199
+ .eq('bucket_id', 'uploads')
200
+ .lt('created_at', cutoff)
201
+
202
+ if (orphans?.length) {
203
+ const paths = orphans.map(o => o.name)
204
+ // Delete in batches of 100
205
+ for (let i = 0; i < paths.length; i += 100) {
206
+ await supabaseAdmin.storage
207
+ .from('uploads')
208
+ .remove(paths.slice(i, i + 100))
209
+ }
210
+ console.log(`Cleaned ${orphans.length} orphaned files`)
211
+ }
109
212
  }
110
213
  ```
111
214
 
112
- ### Step 2: Batching Requests
113
- ```typescript
114
- // Instead of N individual calls
115
- await Promise.all(ids.map(id => supabaseClient.get(id)));
215
+ **Bandwidth reduction select only what you need:**
116
216
 
117
- // Use batch endpoint (1 call)
118
- await supabaseClient.batchGet(ids);
217
+ ```typescript
218
+ // BAD: transfers entire row (wastes bandwidth)
219
+ const { data } = await supabase.from('products').select('*')
220
+
221
+ // GOOD: request only needed columns
222
+ const { data } = await supabase.from('products').select('id, name, price')
223
+
224
+ // Use count queries for totals (head: true = zero data transferred)
225
+ const { count } = await supabase
226
+ .from('orders')
227
+ .select('*', { count: 'exact', head: true })
228
+
229
+ // Paginate large result sets
230
+ const { data } = await supabase
231
+ .from('logs')
232
+ .select('id, message, created_at')
233
+ .order('created_at', { ascending: false })
234
+ .range(0, 49) // 50 rows per page
119
235
  ```
120
236
 
121
- ### Step 3: Caching (from P16)
122
- - Cache frequently accessed data
123
- - Use cache invalidation webhooks
124
- - Set appropriate TTLs
237
+ ### Step 3: Right-Size Compute and Reduce Edge Function Costs
238
+
239
+ **Connection pooling with Supavisor** (reduces need for compute upgrades):
125
240
 
126
- ### Step 4: Compression
127
241
  ```typescript
128
- const client = new SupabaseClient({
129
- compression: true, // Enable gzip
130
- });
242
+ // Use the pooler connection string instead of direct connection
243
+ // Dashboard > Settings > Database > Connection string > Mode: Transaction
244
+
245
+ // In your app, use the pooled connection URL (port 6543)
246
+ // Direct: postgresql://postgres:pw@db.xxx.supabase.co:5432/postgres
247
+ // Pooled: postgresql://postgres:pw@db.xxx.supabase.co:6543/postgres
248
+
249
+ // For @supabase/supabase-js, connection pooling is handled automatically
250
+ // For direct pg connections (migrations, ORMs), use pooled URL:
251
+ const pool = new Pool({
252
+ connectionString: process.env.DATABASE_URL, // Use pooler URL
253
+ max: 10, // Limit client-side pool size too
254
+ })
131
255
  ```
132
256
 
133
- ## Budget Alerts
257
+ **Edge Function cold start reduction:**
134
258
 
135
- ```bash
136
- # Set up billing alerts in Supabase dashboard
137
- # Or use API if available:
138
- # Check Supabase documentation for billing APIs
139
- ```
259
+ ```typescript
260
+ // Minimize cold starts keep imports lightweight
261
+ // BAD: importing heavy libraries unconditionally
262
+ import { parse } from 'some-huge-csv-library'
140
263
 
141
- ## Cost Dashboard Query
264
+ // GOOD: dynamic import only when needed
265
+ Deno.serve(async (req) => {
266
+ const { action } = await req.json()
142
267
 
143
- ```sql
144
- -- If tracking usage in your database
145
- SELECT
146
- DATE_TRUNC('day', created_at) as date,
147
- COUNT(*) as requests,
148
- SUM(response_bytes) as bytes,
149
- COUNT(*) * 0.001 as estimated_cost
150
- FROM supabase_api_logs
151
- WHERE created_at >= NOW() - INTERVAL '30 days'
152
- GROUP BY 1
153
- ORDER BY 1;
154
- ```
268
+ if (action === 'parse-csv') {
269
+ const { parse } = await import('some-huge-csv-library')
270
+ return new Response(JSON.stringify(parse(data)))
271
+ }
155
272
 
156
- ## Instructions
273
+ // Fast path: no heavy import needed
274
+ return new Response(JSON.stringify({ status: 'ok' }))
275
+ })
157
276
 
158
- ### Step 1: Analyze Current Usage
159
- Review Supabase dashboard for usage patterns and costs.
277
+ // Cache expensive computations across invocations
278
+ // Deno Deploy isolates persist for ~60 seconds between requests
279
+ const _cache = new Map<string, { data: unknown; ts: number }>()
160
280
 
161
- ### Step 2: Select Optimal Tier
162
- Use the cost estimation function to find the right tier.
281
+ function cached<T>(key: string, ttlMs: number, fn: () => T): T {
282
+ const entry = _cache.get(key)
283
+ if (entry && Date.now() - entry.ts < ttlMs) return entry.data as T
284
+ const data = fn()
285
+ _cache.set(key, { data, ts: Date.now() })
286
+ return data
287
+ }
288
+ ```
163
289
 
164
- ### Step 3: Implement Monitoring
165
- Add usage tracking to catch budget overruns early.
290
+ **Usage monitoring track spend with a lightweight counter:**
166
291
 
167
- ### Step 4: Apply Optimizations
168
- Enable batching, caching, and sampling where appropriate.
292
+ ```sql
293
+ -- Create usage tracking table
294
+ create table public.api_usage (
295
+ id bigint generated always as identity primary key,
296
+ endpoint text not null,
297
+ method text not null,
298
+ user_id uuid references auth.users(id),
299
+ response_bytes int default 0,
300
+ created_at timestamptz default now()
301
+ );
302
+
303
+ -- Create partitioned index for efficient time-range queries
304
+ create index idx_api_usage_created on public.api_usage (created_at desc);
305
+
306
+ -- Materialized view for daily cost estimation
307
+ create materialized view public.daily_usage_summary as
308
+ select
309
+ date_trunc('day', created_at) as day,
310
+ endpoint,
311
+ count(*) as requests,
312
+ sum(response_bytes) as total_bytes
313
+ from public.api_usage
314
+ group by 1, 2;
315
+
316
+ -- Auto-refresh via pg_cron (enable extension first)
317
+ select cron.schedule(
318
+ 'refresh-usage-summary',
319
+ '0 1 * * *',
320
+ 'refresh materialized view concurrently public.daily_usage_summary;'
321
+ );
322
+ ```
169
323
 
170
324
  ## Output
171
- - Optimized tier selection
172
- - Usage monitoring implemented
173
- - Budget alerts configured
174
- - Cost reduction strategies applied
325
+
326
+ After completing all three steps, you will have:
327
+
328
+ - Database size audit with table-level breakdown and dead tuple analysis
329
+ - Unused indexes identified and dropped to reclaim storage
330
+ - Old data archived and vacuumed to free database space
331
+ - Storage orphans cleaned and upload compression implemented
332
+ - Bandwidth reduced through column selection and pagination
333
+ - Connection pooling configured to avoid unnecessary compute upgrades
334
+ - Edge Function cold starts minimized with dynamic imports and caching
335
+ - Usage monitoring table and daily summary view for spend visibility
175
336
 
176
337
  ## Error Handling
338
+
177
339
  | Issue | Cause | Solution |
178
340
  |-------|-------|----------|
179
- | Unexpected charges | Untracked usage | Implement monitoring |
180
- | Overage fees | Wrong tier | Upgrade tier |
181
- | Budget exceeded | No alerts | Set up alerts |
182
- | Inefficient usage | No batching | Enable batch requests |
341
+ | Database approaching 500 MB (Free) or 8 GB (Pro) | Data growth without archival | Archive old records, VACUUM, drop unused indexes |
342
+ | Storage costs climbing monthly | Orphaned uploads accumulating | Schedule cleanup job for files not linked to records |
343
+ | Unexpected bandwidth spike | `select('*')` on large tables | Use specific column lists; add `.range()` pagination |
344
+ | Edge Function billing spike | Retry loops or heavy imports | Add circuit breaker with max 3 retries; dynamic imports |
345
+ | Connection limit errors | Too many direct connections | Switch to pooler URL (port 6543); reduce client pool size |
346
+ | Spend cap reached | Usage exceeded Pro included resources | Enable spend cap in Dashboard > Settings > Billing to prevent overage |
347
+ | VACUUM not reclaiming space | Long-running transactions holding locks | Check `pg_stat_activity` for idle-in-transaction; terminate stale sessions |
183
348
 
184
349
  ## Examples
185
350
 
186
- ### Quick Cost Check
351
+ **Quick cost check for a growing project:**
352
+
187
353
  ```typescript
188
- // Estimate monthly cost for your usage
189
- const estimate = estimateSupabaseCost(yourMonthlyRequests);
190
- console.log(`Tier: ${estimate.tier}, Cost: $${estimate.estimatedCost}`);
191
- if (estimate.recommendation) {
192
- console.log(`💡 ${estimate.recommendation}`);
354
+ import { createClient } from '@supabase/supabase-js'
355
+
356
+ const supabase = createClient(
357
+ process.env.SUPABASE_URL!,
358
+ process.env.SUPABASE_SERVICE_ROLE_KEY!
359
+ )
360
+
361
+ // Check database size against plan limit
362
+ const { data: dbSize } = await supabase.rpc('get_db_size')
363
+ // CREATE FUNCTION get_db_size() RETURNS text AS $$
364
+ // SELECT pg_size_pretty(pg_database_size(current_database()));
365
+ // $$ LANGUAGE sql;
366
+
367
+ console.log(`Database size: ${dbSize}`)
368
+
369
+ // Check if you're approaching storage limits
370
+ const { data: buckets } = await supabase.storage.listBuckets()
371
+ console.log(`Storage buckets: ${buckets?.length ?? 0}`)
372
+ ```
373
+
374
+ **Monthly cost estimation script:**
375
+
376
+ ```typescript
377
+ function estimateMonthlyCost(usage: {
378
+ dbSizeGb: number
379
+ storageGb: number
380
+ bandwidthGb: number
381
+ edgeFnInvocations: number
382
+ mau: number
383
+ }) {
384
+ const pro = {
385
+ base: 25,
386
+ dbOverage: Math.max(0, usage.dbSizeGb - 8) * 0.125,
387
+ storageOverage: Math.max(0, usage.storageGb - 100) * 0.021,
388
+ bandwidthOverage: Math.max(0, usage.bandwidthGb - 250) * 0.09,
389
+ edgeFnOverage: Math.max(0, usage.edgeFnInvocations - 2_000_000) / 1_000_000 * 2,
390
+ }
391
+
392
+ const total = pro.base + pro.dbOverage + pro.storageOverage
393
+ + pro.bandwidthOverage + pro.edgeFnOverage
394
+
395
+ console.log('Estimated monthly cost breakdown:')
396
+ console.log(` Base Pro plan: $${pro.base}`)
397
+ console.log(` DB overage: $${pro.dbOverage.toFixed(2)}`)
398
+ console.log(` Storage overage: $${pro.storageOverage.toFixed(2)}`)
399
+ console.log(` Bandwidth overage: $${pro.bandwidthOverage.toFixed(2)}`)
400
+ console.log(` Edge Fn overage: $${pro.edgeFnOverage.toFixed(2)}`)
401
+ console.log(` TOTAL: $${total.toFixed(2)}/mo`)
402
+
403
+ return total
193
404
  }
405
+
406
+ // Example: project with 12GB DB, 150GB storage, 300GB bandwidth
407
+ estimateMonthlyCost({
408
+ dbSizeGb: 12,
409
+ storageGb: 150,
410
+ bandwidthGb: 300,
411
+ edgeFnInvocations: 1_500_000,
412
+ mau: 80_000,
413
+ })
414
+ // Base Pro plan: $25
415
+ // DB overage: $0.50
416
+ // Storage overage: $1.05
417
+ // Bandwidth overage: $4.50
418
+ // Edge Fn overage: $0.00
419
+ // TOTAL: $31.05/mo
194
420
  ```
195
421
 
196
422
  ## Resources
197
- - [Supabase Pricing](https://supabase.com/pricing)
198
- - [Supabase Billing Dashboard](https://dashboard.supabase.com/billing)
423
+
424
+ - [Supabase Pricing](https://supabase.com/pricing) — plan comparison and calculator
425
+ - [Compute Add-ons](https://supabase.com/docs/guides/platform/compute-add-ons) — instance sizing guide
426
+ - [Spend Cap](https://supabase.com/docs/guides/platform/spend-cap) — prevent unexpected overage charges
427
+ - [Database Disk Usage](https://supabase.com/docs/guides/platform/database-size) — monitoring and management
428
+ - [Connection Pooling (Supavisor)](https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler) — reduce connection overhead
429
+ - [Edge Functions Best Practices](https://supabase.com/docs/guides/functions/best-practices) — cold start and performance tips
430
+ - [supabase-js Reference](https://supabase.com/docs/reference/javascript/introduction) — `createClient` and SDK patterns
199
431
 
200
432
  ## Next Steps
201
- For architecture patterns, see `supabase-reference-architecture`.
433
+
434
+ For architecture patterns, see `supabase-reference-architecture`.
435
+ For performance tuning beyond cost, see `supabase-performance-tuning`.
@@ -0,0 +1,34 @@
1
+ # Cost Estimation
2
+
3
+ ## Cost Estimation
4
+
5
+ ```typescript
6
+ interface UsageEstimate {
7
+ requestsPerMonth: number;
8
+ tier: string;
9
+ estimatedCost: number;
10
+ recommendation?: string;
11
+ }
12
+
13
+ function estimateSupabaseCost(requestsPerMonth: number): UsageEstimate {
14
+ if (requestsPerMonth <= 1000) {
15
+ return { requestsPerMonth, tier: 'Free', estimatedCost: 0 };
16
+ }
17
+
18
+ if (requestsPerMonth <= 100000) {
19
+ return { requestsPerMonth, tier: 'Pro', estimatedCost: 25 };
20
+ }
21
+
22
+ const proOverage = (requestsPerMonth - 100000) * 0.001;
23
+ const proCost = 25 + proOverage;
24
+
25
+ return {
26
+ requestsPerMonth,
27
+ tier: 'Pro (with overage)',
28
+ estimatedCost: proCost,
29
+ recommendation: proCost > 500
30
+ ? 'Consider Enterprise tier for volume discounts'
31
+ : undefined,
32
+ };
33
+ }
34
+ ```
@@ -0,0 +1,40 @@
1
+ # Cost Reduction Strategies
2
+
3
+ ## Cost Reduction Strategies
4
+
5
+ ### Step 1: Request Sampling
6
+
7
+ ```typescript
8
+ function shouldSample(samplingRate = 0.1): boolean {
9
+ return Math.random() < samplingRate;
10
+ }
11
+
12
+ // Use for non-critical telemetry
13
+ if (shouldSample(0.1)) { // 10% sample
14
+ await supabaseClient.trackEvent(event);
15
+ }
16
+ ```
17
+
18
+ ### Step 2: Batching Requests
19
+
20
+ ```typescript
21
+ // Instead of N individual calls
22
+ await Promise.all(ids.map(id => supabaseClient.get(id)));
23
+
24
+ // Use batch endpoint (1 call)
25
+ await supabaseClient.batchGet(ids);
26
+ ```
27
+
28
+ ### Step 3: Caching (from P16)
29
+
30
+ - Cache frequently accessed data
31
+ - Use cache invalidation webhooks
32
+ - Set appropriate TTLs
33
+
34
+ ### Step 4: Compression
35
+
36
+ ```typescript
37
+ const client = new SupabaseClient({
38
+ compression: true, // Enable gzip
39
+ });
40
+ ```
@@ -0,0 +1,11 @@
1
+ # Error Handling Reference
2
+
3
+ | Issue | Cause | Solution |
4
+ |-------|-------|----------|
5
+ | Unexpected charges | Untracked usage | Implement monitoring |
6
+ | Overage fees | Wrong tier | Upgrade tier |
7
+ | Budget exceeded | No alerts | Set up alerts |
8
+ | Inefficient usage | No batching | Enable batch requests |
9
+
10
+ ---
11
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
@@ -0,0 +1,15 @@
1
+ ## Examples
2
+
3
+ ### Quick Cost Check
4
+
5
+ ```typescript
6
+ // Estimate monthly cost for your usage
7
+ const estimate = estimateSupabaseCost(yourMonthlyRequests);
8
+ console.log(`Tier: ${estimate.tier}, Cost: $${estimate.estimatedCost}`);
9
+ if (estimate.recommendation) {
10
+ console.log(`💡 ${estimate.recommendation}`);
11
+ }
12
+ ```
13
+
14
+ ---
15
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*