mirror of
https://github.com/supabase/supabase.git
synced 2026-09-09 19:42:46 +08:00
Closes DOCS-1260 _See WAVE plugin no longer flags a jump in header hierarchy. Preview on left._ <img width="708" height="699" alt="Screenshot 2026-07-29 at 2 30 11 PM" src="https://github.com/user-attachments/assets/be5bf335-9e03-474f-8215-06fa505ab2db" /> ## Problem Beyond the 4 shared components fixed in [#48456](https://github.com/supabase/supabase/pull/48456), the [header hierarchy report](https://app.notion.com/p/supabase/Playwright-E2E-Triage-Reports-3ab5004b775f81e3bc60d058fa5a02c1) found plain content headings that skip a level. For example, you may see a `##` followed directly by an `####`. Jumps in headers breaks page navigation for screen reader users, who jump between headings expecting each level to nest one at a time. ## Solution Adjusted heading levels across the affected guide and troubleshooting pages so every section nests correctly, with no skipped levels. **Staging previews:** | Page | Preview | | --- | --- | | `/guides/api/rest/postgrest-error-codes` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/api/rest/postgrest-error-codes) | | `/guides/auth/oauth-server/getting-started` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/auth/oauth-server/getting-started) | | `/guides/database/custom-postgres-config` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/database/custom-postgres-config) | | `/guides/database/drizzle` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/database/drizzle) | | `/guides/database/extensions` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/database/extensions) | | `/guides/database/extensions/pgaudit` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/database/extensions/pgaudit) | | `/guides/database/postgres-js` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/database/postgres-js) | | `/guides/database/replication/manual-replication-monitoring` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/database/replication/manual-replication-monitoring) | | `/guides/database/replication/manual-replication-setup` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/database/replication/manual-replication-setup) | | `/guides/database/replication/pipelines-monitoring` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/database/replication/pipelines-monitoring) | | `/guides/functions/debugging-tools` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/functions/debugging-tools) | | `/guides/functions/development-tips` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/functions/development-tips) | | `/guides/functions/examples/auth-send-email-hook-react-email-resend` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/functions/examples/auth-send-email-hook-react-email-resend) | | `/guides/functions/examples/image-manipulation` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/functions/examples/image-manipulation) | | `/guides/functions/examples/semantic-search` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/functions/examples/semantic-search) | | `/guides/functions/examples/send-emails` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/functions/examples/send-emails) | | `/guides/functions/examples/sentry-monitoring` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/functions/examples/sentry-monitoring) | | `/guides/functions/wasm` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/functions/wasm) | | `/guides/getting-started` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/getting-started) | | `/guides/platform/aws-marketplace` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/platform/aws-marketplace) | | `/guides/platform/aws-marketplace/faq` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/platform/aws-marketplace/faq) | | `/guides/platform/billing-faq` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/platform/billing-faq) | | `/guides/platform/ipv4-address` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/platform/ipv4-address) | | `/guides/platform/migrating-within-supabase/backup-restore` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/platform/migrating-within-supabase/backup-restore) | | `/guides/platform/privatelink` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/platform/privatelink) | | `/guides/queues/api` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/queues/api) | | `/guides/resources` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/resources) | | `/guides/security/hipaa-compliance` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/security/hipaa-compliance) | | `/guides/security/security-testing` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/security/security-testing) | | `/guides/security/soc-2-compliance` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/security/soc-2-compliance) | | `/guides/self-hosting` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/self-hosting) | | `/guides/storage/cdn/fundamentals` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/storage/cdn/fundamentals) | | `/guides/storage/debugging/logs` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/storage/debugging/logs) | | `/guides/storage/production/scaling` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/storage/production/scaling) | | `/guides/storage/schema/helper-functions` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/storage/schema/helper-functions) | | `/guides/storage/serving/image-transformations` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/storage/serving/image-transformations) | | `/guides/storage/uploads/resumable-uploads` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/storage/uploads/resumable-uploads) | | `/guides/troubleshooting/an-invalid-response-was-received-from-the-upstream-server-error-when-querying-auth-RI4Vl-` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/an-invalid-response-was-received-from-the-upstream-server-error-when-querying-auth-RI4Vl-) | | `/guides/troubleshooting/are-all-features-available-in-self-hosted-supabase-THPcqw` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/are-all-features-available-in-self-hosted-supabase-THPcqw) | | `/guides/troubleshooting/avoiding-timeouts-in-long-running-queries-6nmbdN` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/avoiding-timeouts-in-long-running-queries-6nmbdN) | | `/guides/troubleshooting/database-api-42501-errors` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/database-api-42501-errors) | | `/guides/troubleshooting/disabling-prepared-statements-qL8lEL` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/disabling-prepared-statements-qL8lEL) | | `/guides/troubleshooting/discovering-and-interpreting-api-errors-in-the-logs-7xREI9` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/discovering-and-interpreting-api-errors-in-the-logs-7xREI9) | | `/guides/troubleshooting/edge-function-504-error-response` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/edge-function-504-error-response) | | `/guides/troubleshooting/high-cpu-and-slow-queries-with-error-must-be-a-superuser-to-terminate-superuser-process` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/high-cpu-and-slow-queries-with-error-must-be-a-superuser-to-terminate-superuser-process) | | `/guides/troubleshooting/how-postgres-chooses-which-index-to-use-_JHrf4` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/how-postgres-chooses-which-index-to-use-_JHrf4) | | `/guides/troubleshooting/how-to-change-max-database-connections-_BQ8P5` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/how-to-change-max-database-connections-_BQ8P5) | | `/guides/troubleshooting/how-to-interpret-and-explore-the-postgres-logs-OuCIOj` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/how-to-interpret-and-explore-the-postgres-logs-OuCIOj) | | `/guides/troubleshooting/how-to-migrate-from-supabase-auth-helpers-to-ssr-package-5NRunM` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/how-to-migrate-from-supabase-auth-helpers-to-ssr-package-5NRunM) | | `/guides/troubleshooting/http-api-issues` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/http-api-issues) | | `/guides/troubleshooting/increase-vector-lookup-speeds-by-applying-an-hsnw-index-ohLHUM` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/increase-vector-lookup-speeds-by-applying-an-hsnw-index-ohLHUM) | | `/guides/troubleshooting/interpreting-supabase-grafana-cpu-charts-9JSlkC` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/interpreting-supabase-grafana-cpu-charts-9JSlkC) | | `/guides/troubleshooting/interpreting-supabase-grafana-io-charts-MUynDR` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/interpreting-supabase-grafana-io-charts-MUynDR) | | `/guides/troubleshooting/new-branch-doesnt-copy-database` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/new-branch-doesnt-copy-database) | | `/guides/troubleshooting/not-receiving-auth-emails-from-the-supabase-project-OFSNzw` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/not-receiving-auth-emails-from-the-supabase-project-OFSNzw) | | `/guides/troubleshooting/resolving-500-status-authentication-errors-7bU5U8` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/resolving-500-status-authentication-errors-7bU5U8) | | `/guides/troubleshooting/resolving-cannot-execute-update-in-a-read-only-transaction-on-transaction-pooler-connections-ef582c` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/resolving-cannot-execute-update-in-a-read-only-transaction-on-transaction-pooler-connections-ef582c) | | `/guides/troubleshooting/resolving-database-hostname-and-managing-your-ip-address-pVlwE0` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/resolving-database-hostname-and-managing-your-ip-address-pVlwE0) | | `/guides/troubleshooting/rls-simplified-BJTcS8` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/rls-simplified-BJTcS8) | | `/guides/troubleshooting/security-of-anonymous-sign-ins-iOrGCL` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/security-of-anonymous-sign-ins-iOrGCL) | | `/guides/troubleshooting/supabase--your-network-ipv4-and-ipv6-compatibility-cHe3BP` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/supabase--your-network-ipv4-and-ipv6-compatibility-cHe3BP) | | `/guides/troubleshooting/supabase-grafana-memory-charts` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/supabase-grafana-memory-charts) | | `/guides/troubleshooting/supavisor-faq-YyP5tI` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/supavisor-faq-YyP5tI) | | `/guides/troubleshooting/tracking-postgres-role-activity-to-specific-dashboard-users-8d3715` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/tracking-postgres-role-activity-to-specific-dashboard-users-8d3715) | | `/guides/troubleshooting/transferring-from-cloud-to-self-host-in-supabase-2oWNvW` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/transferring-from-cloud-to-self-host-in-supabase-2oWNvW) | | `/guides/troubleshooting/understanding-postgresql-explain-output-Un9dqX` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/understanding-postgresql-explain-output-Un9dqX) | | `/guides/troubleshooting/understanding-postgresql-logging-levels-and-how-they-impact-your-project-KXiJRm` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/understanding-postgresql-logging-levels-and-how-they-impact-your-project-KXiJRm) | | `/guides/troubleshooting/vercel-integration-environment-variables-not-syncing-for-persistent-git-branches-b9191e` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/vercel-integration-environment-variables-not-syncing-for-persistent-git-branches-b9191e) | | `/guides/troubleshooting/why-are-there-gaps-in-my-postgres-id-sequence-Frifus` | [Preview](https://docs-git-docs-heading-hierarchy-supabase.vercel.app/docs/guides/troubleshooting/why-are-there-gaps-in-my-postgres-id-sequence-Frifus) | ## Manual testing 1. See affected pages. Recommend running a browser plugin like WAVE and selecting the **Structure** tab. 2. See the headings do not skip. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Documentation** * Standardized heading hierarchy across many guides and troubleshooting articles to improve readability and navigation. * Updated several documentation link targets to the correct new locations. * Reformatted multiple sections (including replication monitoring, Edge Functions, Storage, authentication, security, and networking) without changing instructions. * Queue Data API docs were restructured via heading-level adjustments (no operational changes). * Billing FAQ received clearer, more detailed payment-failure and tax guidance, plus related link updates. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
105 lines
4.5 KiB
Plaintext
105 lines
4.5 KiB
Plaintext
---
|
|
id: 'functions-development-tips'
|
|
title: 'Development tips'
|
|
description: 'Tips for getting started with Edge Functions.'
|
|
subtitle: 'Tips for getting started with Edge Functions.'
|
|
---
|
|
|
|
Here are a few recommendations when you first start developing Edge Functions.
|
|
|
|
## Using HTTP methods
|
|
|
|
Edge Functions support `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, and `OPTIONS`. A Function can be designed to perform different actions based on a request's HTTP method. See the [example on building a RESTful service](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/restful-tasks) to learn how to handle different HTTP methods in your Function.
|
|
|
|
<Admonition type="caution" title="HTML not supported">
|
|
|
|
HTML content is not supported. `GET` requests that return `text/html` will be rewritten to `text/plain`.
|
|
|
|
</Admonition>
|
|
|
|
## Naming Edge Functions
|
|
|
|
We recommend using hyphens to name functions because hyphens are the most URL-friendly of all the naming conventions (snake_case, camelCase, PascalCase).
|
|
|
|
## Organizing your Edge Functions
|
|
|
|
We recommend developing "fat functions". This means that you should develop few large functions, rather than many small functions. One common pattern when developing Functions is that you need to share code between two or more Functions. To do this, you can store any shared code in a folder prefixed with an underscore (`_`). We also recommend a separate folder for [Unit Tests](/docs/guides/functions/unit-test) including the name of the function followed by a `-test` suffix.
|
|
We recommend this folder structure:
|
|
|
|
```bash
|
|
└── supabase
|
|
├── functions
|
|
│ ├── import_map.json # A top-level import map to use across functions.
|
|
│ ├── _shared
|
|
│ │ ├── supabaseAdmin.ts # Supabase client with SECRET key.
|
|
│ │ └── supabaseClient.ts # Supabase client with PUBLISHABLE key.
|
|
│ │ └── cors.ts # Reusable CORS headers.
|
|
│ ├── function-one # Use hyphens to name functions.
|
|
│ │ └── index.ts
|
|
│ └── function-two
|
|
│ │ └── index.ts
|
|
│ └── tests
|
|
│ └── function-one-test.ts
|
|
│ └── function-two-test.ts
|
|
├── migrations
|
|
└── config.toml
|
|
```
|
|
|
|
## Using config.toml
|
|
|
|
Individual function configuration like [JWT verification](/docs/guides/local-development/cli/config#functions.function_name.verify_jwt) and [import map location](/docs/guides/local-development/cli/config#functions.function_name.import_map) can be set via the `config.toml` file.
|
|
|
|
```toml supabase/config.toml
|
|
[functions.hello-world]
|
|
verify_jwt = false
|
|
import_map = './import_map.json'
|
|
```
|
|
|
|
## Not using TypeScript
|
|
|
|
When you create a new Edge Function, it will use TypeScript by default. However, it is possible to write and deploy Edge Functions using pure JavaScript.
|
|
|
|
Save your Function as a JavaScript file (e.g. `index.js`) and then update the `supabase/config.toml` as follows:
|
|
|
|
<Admonition type="note">
|
|
|
|
`entrypoint` is available only in Supabase CLI version 1.215.0 or higher.
|
|
|
|
</Admonition>
|
|
|
|
```toml supabase/config.toml
|
|
[functions.hello-world]
|
|
# other entries
|
|
entrypoint = './functions/hello-world/index.js' # path must be relative to config.toml
|
|
```
|
|
|
|
You can use any `.ts`, `.js`, `.tsx`, `.jsx` or `.mjs` file as the `entrypoint` for a Function.
|
|
|
|
## Error handling
|
|
|
|
The `supabase-js` library provides several error types that you can use to handle errors that might occur when invoking Edge Functions:
|
|
|
|
```js
|
|
import { FunctionsFetchError, FunctionsHttpError, FunctionsRelayError } from '@supabase/supabase-js'
|
|
|
|
const { data, error } = await supabase.functions.invoke('hello', {
|
|
headers: { 'my-custom-header': 'my-custom-header-value' },
|
|
body: { foo: 'bar' },
|
|
})
|
|
|
|
if (error instanceof FunctionsHttpError) {
|
|
const errorMessage = await error.context.json()
|
|
console.log('Function returned an error', errorMessage)
|
|
} else if (error instanceof FunctionsRelayError) {
|
|
console.log('Relay error:', error.message)
|
|
} else if (error instanceof FunctionsFetchError) {
|
|
console.log('Fetch error:', error.message)
|
|
}
|
|
```
|
|
|
|
## Database Functions vs Edge Functions
|
|
|
|
For data-intensive operations we recommend using [Database Functions](/docs/guides/database/functions), which are executed within your database and can be called remotely using the [REST and GraphQL API](/docs/guides/api).
|
|
|
|
For use-cases which require low-latency we recommend [Edge Functions](/docs/guides/functions), which are globally-distributed and can be written in TypeScript.
|