diff --git a/apps/docs/components/MDX/auth_error_codes_table.mdx b/apps/docs/components/MDX/auth_error_codes_table.mdx
index fe20ab0da47..1447eadb689 100644
--- a/apps/docs/components/MDX/auth_error_codes_table.mdx
+++ b/apps/docs/components/MDX/auth_error_codes_table.mdx
@@ -17,6 +17,7 @@ To supplement HTTP status codes, Supabase Auth returns a string error code which
| `email_provider_disabled` | Signups are disabled for email and password. |
| `flow_state_expired` | PKCE flow state to which the API request relates has expired. Ask the user to sign in again. |
| `flow_state_not_found` | PKCE flow state to which the API request relates no longer exists. Flow states expire after a while and are progressively cleaned up, which can cause this error. Retried requests can cause this error, as the previous request likely destroyed the flow state. Ask the user to sign in again. |
+| `hook_payload_invalid_content_type` | Payload from Auth does not have a valid Content-Type header. |
| `hook_payload_over_size_limit` | Payload from Auth exceeds maximum size limit. |
| `hook_timeout` | Unable to reach hook within maximum time allocated. |
| `hook_timeout_after_retry` | Unable to reach hook after maximum number of retries. |
@@ -30,13 +31,15 @@ To supplement HTTP status codes, Supabase Auth returns a string error code which
| `mfa_factor_name_conflict` | MFA factors for a single user should not have the same friendly name. |
| `mfa_factor_not_found` | MFA factor no longer exists. |
| `mfa_ip_address_mismatch` | The enrollment process for MFA factors must begin and end with the same IP address. |
+| `mfa_phone_enroll_not_enabled` | Enrollment of MFA Phone factors is disabled. |
+| `mfa_phone_verify_not_enabled` | Login via Phone factors and verification of new Phone factors is disabled. |
+| `mfa_totp_enroll_not_enabled` | Enrollment of MFA TOTP factors is disabled. |
+| `mfa_totp_verify_not_enabled` | Login via TOTP factors and verification of new TOTP factors is disabled. |
| `mfa_verification_failed` | MFA challenge could not be verified -- wrong TOTP code. |
| `mfa_verification_rejected` | Further MFA verification is rejected. Only returned if the [MFA verification attempt hook](https://supabase.com/docs/guides/auth/auth-hooks?language=add-admin-role#hook-mfa-verification-attempt) returns a reject decision. |
| `mfa_verified_factor_exists` | Verified phone factor already exists for a user. Unenroll existing verified phone factor to continue. |
-| `mfa_totp_enroll_disabled` | Enrollment of MFA TOTP factors is disabled. |
-| `mfa_totp_verify_disabled` | Login via TOTP factors and verification of new TOTP factors is disabled. |
-| `mfa_phone_enroll_disabled` | Enrollment of MFA Phone factors is disabled. |
-| `mfa_phone_verify_disabled` | Login via Phone factors and verification of new Phone factors is disabled. |
+| `mfa_web_authn_enroll_not_enabled` | Enrollment of MFA Web Authn factors is disabled. |
+| `mfa_web_authn_verify_not_enabled` | Login via WebAuthn factors and verification of new WebAuthn factors is disabled. |
| `no_authorization` | This HTTP request requires an `Authorization` header, which is not provided. |
| `not_admin` | User accessing the API is not admin, i.e. the JWT does not contain a `role` claim that identifies them as an admin of the Auth server. |
| `oauth_provider_not_supported` | Using an OAuth provider which is disabled on the Auth server. |
@@ -52,6 +55,8 @@ To supplement HTTP status codes, Supabase Auth returns a string error code which
| `provider_email_needs_verification` | Not all OAuth providers verify their user's email address. Supabase Auth requires emails to be verified, so this error is sent out when a verification email is sent after completing the OAuth flow. |
| `reauthentication_needed` | A user needs to reauthenticate to change their password. Ask the user to reauthenticate by calling the `supabase.auth.reauthenticate()` API. |
| `reauthentication_not_valid` | Verifying a reauthentication failed, the code is incorrect. Ask the user to enter a new code. |
+| `refresh_token_not_found` | Session containing the refresh token not found. |
+| `refresh_token_already_used` | Refresh token has been revoked and falls outside the refresh token reuse interval. See the [documentation on sessions](https://supabase.com/docs/guides/auth/sessions) for further information. |
| `request_timeout` | Processing the request took too long. Retry the request. |
| `same_password` | A user that is updating their password must use a different password than the one currently used. |
| `saml_assertion_no_email` | SAML assertion (user information) was received after sign in, but no email address was found in it, which is required. Check the provider's attribute mapping and/or configuration. |
@@ -63,6 +68,7 @@ To supplement HTTP status codes, Supabase Auth returns a string error code which
| `saml_provider_disabled` | Using [Enterprise SSO with SAML 2.0](https://supabase.com/docs/guides/auth/enterprise-sso/auth-sso-saml) is not enabled on the Auth server. |
| `saml_relay_state_expired` | SAML relay state is an object that tracks the progress of a `supabase.auth.signInWithSSO()` request. The SAML identity provider should respond after a fixed amount of time, after which this error is shown. Ask the user to sign in again. |
| `saml_relay_state_not_found` | SAML relay states are progressively cleaned up after they expire, which can cause this error. Ask the user to sign in again. |
+| `session_expired` | Session to which the API request relates has expired. This can occur if an inactivity timeout is configured, or the session entry has exceeded the configured timebox value. See the [documentation on sessions](https://supabase.com/docs/guides/auth/sessions) for more information. |
| `session_not_found` | Session to which the API request relates no longer exists. This can occur if the user has signed out, or the session entry in the database was deleted in some other way. |
| `signup_disabled` | Sign ups (new account creation) are disabled on the server. |
| `single_identity_not_deletable` | Every user must have at least one identity attached to it, so deleting (unlinking) an identity is not allowed if it's the only one for the user. |
diff --git a/apps/docs/components/Navigation/NavigationMenu/MenuIconPicker.tsx b/apps/docs/components/Navigation/NavigationMenu/MenuIconPicker.tsx
index 5f957a2b7a7..24358664a09 100644
--- a/apps/docs/components/Navigation/NavigationMenu/MenuIconPicker.tsx
+++ b/apps/docs/components/Navigation/NavigationMenu/MenuIconPicker.tsx
@@ -1,4 +1,4 @@
-import { Heart, Server } from 'lucide-react'
+import { Clock, Heart, Server, SquareStack } from 'lucide-react'
import {
IconBranching,
@@ -93,6 +93,10 @@ function getMenuIcon(menuKey: string, width: number = 16, height: number = 16, c
return
case 'deployment':
return
+ case 'cron':
+ return
+ case 'queues':
+ return
default:
return
}
diff --git a/apps/docs/components/Navigation/NavigationMenu/MenuIcons.tsx b/apps/docs/components/Navigation/NavigationMenu/MenuIcons.tsx
index c9dfa878980..353214ce46e 100644
--- a/apps/docs/components/Navigation/NavigationMenu/MenuIcons.tsx
+++ b/apps/docs/components/Navigation/NavigationMenu/MenuIcons.tsx
@@ -1,4 +1,4 @@
-import { products } from 'shared-data'
+import { PRODUCT_MODULES, products } from 'shared-data'
type HomeMenuIcon = {
width?: number
@@ -450,7 +450,7 @@ export function IconMenuAI({ width = 16, height = 16, className }: HomeMenuIcon)
xmlns="http://www.w3.org/2000/svg"
>
[]
+ additionalNavItems?: Record[]>
}) => {
const level = menuId
const menu = getMenuById(level)
diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts
index a723fbceb93..94c31dd2b0d 100644
--- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts
@@ -109,8 +109,8 @@ export const getMenuId = (pathname: string | null) => {
return MenuId.Api
case pathname.startsWith('auth'):
return MenuId.Auth
- case pathname.startsWith('local-development'):
- return MenuId.LocalDevelopment
+ case pathname.startsWith('cron'):
+ return MenuId.Cron
case pathname.startsWith('database'):
return MenuId.Database
case pathname.startsWith('deployment'):
@@ -123,10 +123,14 @@ export const getMenuId = (pathname: string | null) => {
return MenuId.Graphql
case pathname.startsWith('integrations'):
return MenuId.Integrations
+ case pathname.startsWith('local-development'):
+ return MenuId.LocalDevelopment
case pathname.startsWith('monitoring-troubleshooting'):
return MenuId.MonitoringTroubleshooting
case pathname.startsWith('platform'):
return MenuId.Platform
+ case pathname.startsWith('queues'):
+ return MenuId.Queues
case pathname.startsWith('realtime'):
return MenuId.Realtime
case pathname.startsWith('resources'):
diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx
index af40ab7e9e8..e9e211a8265 100644
--- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx
@@ -6,20 +6,23 @@ import { type NavMenuSection } from '../Navigation.types'
import * as NavItems from './NavigationMenu.constants'
import NavigationMenuGuideListItems from './NavigationMenuGuideListItems'
import { usePathname } from 'next/navigation'
+import { PropsWithChildren } from 'react'
+import { MenuId } from './NavigationMenu'
const NavigationMenuGuideList = ({
id,
additionalNavItems,
}: {
id: string
- additionalNavItems?: Partial[]
+ additionalNavItems?: Record[]>
}) => {
const pathname = usePathname()
const firstLevelRoute = pathname?.split('/')?.slice(0, 4)?.join('/')
+ // eslint-disable-next-line import/namespace -- dynamic access, can't lint properly
let menu = NavItems[id]
- if (id === 'integrations' && additionalNavItems) {
+ if (id === MenuId.Integrations && additionalNavItems?.integrations) {
const integrationsListIndex = menu.items.findIndex((item) => item.name === 'Integrations')
if (integrationsListIndex !== -1) {
menu = {
@@ -28,7 +31,7 @@ const NavigationMenuGuideList = ({
...menu.items.slice(0, integrationsListIndex),
{
...menu.items[integrationsListIndex],
- items: [...menu.items[integrationsListIndex].items, ...additionalNavItems],
+ items: [...menu.items[integrationsListIndex].items, ...additionalNavItems.integrations],
},
...menu.items.slice(integrationsListIndex + 1),
],
@@ -36,6 +39,38 @@ const NavigationMenuGuideList = ({
}
}
+ if (id === MenuId.GettingStarted && additionalNavItems?.prompts) {
+ const promptsSectionIndex = menu.items.findIndex((item) => item.name === 'AI Prompts')
+ if (promptsSectionIndex !== -1) {
+ menu = {
+ ...menu,
+ items: [
+ ...menu.items.slice(0, promptsSectionIndex),
+ {
+ ...menu.items[promptsSectionIndex],
+ items: [...menu.items[promptsSectionIndex].items, ...additionalNavItems.prompts],
+ },
+ ...menu.items.slice(promptsSectionIndex + 1),
+ ],
+ }
+ }
+ }
+
+ return (
+
+
+
+ )
+}
+
+export function NavigationMenuGuideListWrapper({
+ id,
+ firstLevelRoute,
+ children,
+}: PropsWithChildren<{
+ id: string
+ firstLevelRoute?: string
+}>) {
return (
-
+ {children}
)
}
diff --git a/apps/docs/content/guides/ai/examples/semantic-image-search-amazon-titan.mdx b/apps/docs/content/guides/ai/examples/semantic-image-search-amazon-titan.mdx
index c2dd616366e..373720b7797 100644
--- a/apps/docs/content/guides/ai/examples/semantic-image-search-amazon-titan.mdx
+++ b/apps/docs/content/guides/ai/examples/semantic-image-search-amazon-titan.mdx
@@ -28,7 +28,7 @@ Then initialize a new project:
poetry new aws_bedrock_image_search
```
-## Spin up a Postgres Database with pgvector
+## Spin up a Postgres database with pgvector
If you haven't already, head over to [database.new](https://database.new) and create a new project. Every Supabase project comes with a full Postgres database and the [pgvector extension](/docs/guides/database/extensions/pgvector) preconfigured.
diff --git a/apps/docs/content/guides/ai/integrations/amazon-bedrock.mdx b/apps/docs/content/guides/ai/integrations/amazon-bedrock.mdx
index d18f9a6bc83..02699d3271d 100644
--- a/apps/docs/content/guides/ai/integrations/amazon-bedrock.mdx
+++ b/apps/docs/content/guides/ai/integrations/amazon-bedrock.mdx
@@ -10,7 +10,7 @@ tocVideo: 'A3uND5sgiO0'
This guide will walk you through an example using Amazon Bedrock SDK with `vecs`. We will create embeddings using the Amazon Titan Embeddings G1 – Text v1.2 (amazon.titan-embed-text-v1) model, insert these embeddings into a PostgreSQL database using vecs, and then query the collection to find the most similar sentences to a given query sentence.
-## Create an Environment
+## Create an environment
First, you need to set up your environment. You will need Python 3.7+ with the `vecs` and `boto3` libraries installed.
@@ -25,7 +25,7 @@ You'll also need:
- [Credentials to your AWS account](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html)
- [A Postgres Database with the pgvector extension](hosting.md)
-## Create Embeddings
+## Create embeddings
Next, we will use Amazon’s Titan Embedding G1 - Text v1.2 model to create embeddings for a set of sentences.
@@ -67,7 +67,7 @@ for sentence in dataset:
```
-### Store the Embeddings with vecs
+### Store the embeddings with vecs
Now that we have our embeddings, we can insert them into a PostgreSQL database using vecs.
@@ -90,7 +90,7 @@ sentences.upsert(records=embeddings)
sentences.create_index()
```
-### Querying for Most Similar Sentences
+### Querying for most similar sentences
Now, we query the `sentences` collection to find the most similar sentences to a sample query sentence. First need to create an embedding for the query sentence. Next, we query the collection we created earlier to find the most similar sentences.
diff --git a/apps/docs/content/guides/ai/structured-unstructured.mdx b/apps/docs/content/guides/ai/structured-unstructured.mdx
index 52872c07c71..7195197a80f 100644
--- a/apps/docs/content/guides/ai/structured-unstructured.mdx
+++ b/apps/docs/content/guides/ai/structured-unstructured.mdx
@@ -24,7 +24,7 @@ values
('79409372-7556-4ccc-ab8f-5786a6cfa4f7', array[0.1, 0.2, 0.3], 'Hello world', '/hello-world');
```
-Notice that we've associated two pieces of metadata, `content` and `url`, with the embedding. Those fields can be filtered, constrained, indexed, and generally operated on using the full power of SQL. Structured metadata fits naturally with a traditional Supabase application, and can be managed via database [migrations](/docs/guides/getting-started/local-development#database-migrations).
+Notice that we've associated two pieces of metadata, `content` and `url`, with the embedding. Those fields can be filtered, constrained, indexed, and generally operated on using the full power of SQL. Structured metadata fits naturally with a traditional Supabase application, and can be managed via database [migrations](/docs/guides/deployment/database-migrations).
## Unstructured
diff --git a/apps/docs/content/guides/api/rest/generating-types.mdx b/apps/docs/content/guides/api/rest/generating-types.mdx
index 6fafcc323dd..c5cf62d86e8 100644
--- a/apps/docs/content/guides/api/rest/generating-types.mdx
+++ b/apps/docs/content/guides/api/rest/generating-types.mdx
@@ -37,13 +37,13 @@ npx supabase init
Generate types for your project to produce the `database.types.ts` file:
```bash
-npx supabase gen types --lang=typescript --project-id "$PROJECT_REF" --schema public > database.types.ts
+npx supabase gen types typescript --project-id "$PROJECT_REF" --schema public > database.types.ts
```
or in case of local development:
```bash
-npx supabase gen types --lang=typescript --local > database.types.ts
+npx supabase gen types typescript --local > database.types.ts
```
These types are generated from your database schema. Given a table `public.movies`, the generated types will look like:
diff --git a/apps/docs/content/guides/api/sql-to-api.mdx b/apps/docs/content/guides/api/sql-to-api.mdx
index 619e7bf7a3c..2e2183d0766 100644
--- a/apps/docs/content/guides/api/sql-to-api.mdx
+++ b/apps/docs/content/guides/api/sql-to-api.mdx
@@ -30,7 +30,7 @@ const { data, error } = await supabase
.limit(20)
```
-## Select statement with complex Boolean Logic clause
+## Select statement with complex Boolean logic clause
Select all columns from a single table with a complex where clause: OR AND OR
diff --git a/apps/docs/content/guides/auth/auth-anonymous.mdx b/apps/docs/content/guides/auth/auth-anonymous.mdx
index cf0ee68c4c7..d1315c41ba4 100644
--- a/apps/docs/content/guides/auth/auth-anonymous.mdx
+++ b/apps/docs/content/guides/auth/auth-anonymous.mdx
@@ -102,7 +102,7 @@ response = supabase.auth.sign_in_anonymously()
Converting an anonymous user to a permanent user requires [linking an identity](/docs/guides/auth/auth-identity-linking#manual-linking-beta) to the user. This requires you to [enable manual linking](/dashboard/project/_/settings/auth) in your Supabase project.
-### Link an Email / Phone identity
+### Link an email / phone identity
-You can use the [`modifyUser()`](/docs/reference/kotlin/auth-updateuser) method to link an email or phone identity to the anonymous user.
+You can use the [`updateUser()`](/docs/reference/kotlin/auth-updateuser) method to link an email or phone identity to the anonymous user.
```kotlin
-supabase.auth.modifyUser {
+supabase.auth.updateUser {
email = "example@email.com"
}
```
diff --git a/apps/docs/content/guides/auth/auth-captcha.mdx b/apps/docs/content/guides/auth/auth-captcha.mdx
index 127640ae192..a55b4e46ab2 100644
--- a/apps/docs/content/guides/auth/auth-captcha.mdx
+++ b/apps/docs/content/guides/auth/auth-captcha.mdx
@@ -1,13 +1,13 @@
---
id: 'auth-captcha'
-title: 'Enable Captcha Protection'
-description: 'Add Captcha Protection to your Supabase project'
+title: 'Enable CAPTCHA Protection'
+description: 'Add CAPTCHA Protection to your Supabase project'
tocVideo: 'em1cpOAXknM'
---
-Supabase provides you with the option of adding captcha to your sign-in, sign-up, and password reset forms. This keeps your website safe from bots and malicious scripts. Supabase authentication has support for [hCaptcha](https://www.hcaptcha.com/) and [Cloudflare Turnstile](https://www.cloudflare.com/products/turnstile/).
+Supabase provides you with the option of adding CAPTCHA to your sign-in, sign-up, and password reset forms. This keeps your website safe from bots and malicious scripts. Supabase authentication has support for [hCaptcha](https://www.hcaptcha.com/) and [Cloudflare Turnstile](https://www.cloudflare.com/products/turnstile/).
-## Sign up for Captcha
+## Sign up for CAPTCHA
-## Enable Captcha protection for your Supabase project
+## Enable CAPTCHA protection for your Supabase project
Navigate to the **[Auth](https://supabase.com/dashboard/project/_/settings/auth)** section of your Project Settings in the Supabase Dashboard and find the **Enable Captcha protection** toggle under Settings > Authentication > Bot and Abuse Protection > Enable Captcha protection.
Select your CAPTCHA provider from the dropdown, enter your Captcha **Secret key**, and click **Save**.
-## Add the Captcha frontend component
+## Add the CAPTCHA frontend component
The frontend requires some changes to provide the captcha on-screen for the user. This example uses React and the corresponding Captcha React component, but both Captcha providers can be used with any JavaScript framework.
diff --git a/apps/docs/content/guides/auth/auth-email-passwordless.mdx b/apps/docs/content/guides/auth/auth-email-passwordless.mdx
index 86e2782c355..5c891e5226f 100644
--- a/apps/docs/content/guides/auth/auth-email-passwordless.mdx
+++ b/apps/docs/content/guides/auth/auth-email-passwordless.mdx
@@ -146,7 +146,7 @@ const { error } = await supabase.auth.verifyOtp({ token_hash, type })
Email one-time passwords (OTP) are a form of passwordless login where users key in a six digit code sent to their email address to log in to their accounts.
-### Enabling Email OTP
+### Enabling email OTP
Email authentication methods, including Email OTPs, are enabled by default.
@@ -162,7 +162,7 @@ Modify the template to include the `{{ .Token }}` variable, for example:
By default, a user can only request an OTP once every auth.rate_limits.otp.period and they expire after auth.rate_limits.otp.validity. This is configurable via `Auth > Providers > Email > Email OTP Expiration`. An expiry duration of more than 86400 seconds (one day) is disallowed to guard against brute force attacks. The longer an OTP remains valid, the more time an attacker has to attempt brute force attacks. If the OTP is valid for several days, an attacker might have more opportunities to guess the correct OTP through repeated attempts.
-### Signing in with Email OTP
+### Signing in with email OTP
#### Step 1: Send the user an OTP code
diff --git a/apps/docs/content/guides/auth/auth-email-templates.mdx b/apps/docs/content/guides/auth/auth-email-templates.mdx
index 265ffd32807..8bed95ba750 100644
--- a/apps/docs/content/guides/auth/auth-email-templates.mdx
+++ b/apps/docs/content/guides/auth/auth-email-templates.mdx
@@ -29,7 +29,7 @@ The templating system provides the following variables for use:
On hosted Supabase projects, edit your email templates on the [Email Templates](/dashboard/project/_/auth/templates) page. On self-hosted projects or in local development, edit your [configuration files](/docs/guides/local-development/customizing-email-templates).
-## Mobile Deep Linking
+## Mobile deep linking
For mobile applications, you might need to link or redirect to a specific page within your app. See the [Mobile Deep Linking guide](/docs/guides/auth/native-mobile-deep-linking) to set this up.
diff --git a/apps/docs/content/guides/auth/auth-helpers/auth-ui.mdx b/apps/docs/content/guides/auth/auth-helpers/auth-ui.mdx
index 296abdf8964..55d96374d17 100644
--- a/apps/docs/content/guides/auth/auth-helpers/auth-ui.mdx
+++ b/apps/docs/content/guides/auth/auth-helpers/auth-ui.mdx
@@ -478,7 +478,7 @@ Setting `showLinks` to `false` will hide the following links:
- Send a magic link email
- Forgot your password?
-### Sign in and Sign up views
+### Sign in and sign up views
Add `sign_in` or `sign_up` views with the `view` prop:
diff --git a/apps/docs/content/guides/auth/auth-hooks.mdx b/apps/docs/content/guides/auth/auth-hooks.mdx
index 9d35a938a5e..94118f245a5 100644
--- a/apps/docs/content/guides/auth/auth-hooks.mdx
+++ b/apps/docs/content/guides/auth/auth-hooks.mdx
@@ -46,7 +46,7 @@ A HTTP Hook is an endpoint which takes in a JSON event payload and returns a JSO
-## Security Model
+## Security model
Sign the payload and grant permissions selectively in order to guard the integrity of the payload.
@@ -261,7 +261,7 @@ Note that payloads are sent uncompressed in order to accurately track Content Le
In the dashboard, navigate to [`Authentication > Hooks`](/dashboard/project/_/auth/hooks) and select the appropriate function type (SQL or HTTP) from the dropdown menu.
-### Error Handling
+### Error handling
You should return an error when facing a runtime error. Runtime errors are specific to your application and arise from specific business rules rather than programmer errors.
diff --git a/apps/docs/content/guides/auth/auth-hooks/send-email-hook.mdx b/apps/docs/content/guides/auth/auth-hooks/send-email-hook.mdx
index c6e2f30ab0b..72be9f5b4fb 100644
--- a/apps/docs/content/guides/auth/auth-hooks/send-email-hook.mdx
+++ b/apps/docs/content/guides/auth/auth-hooks/send-email-hook.mdx
@@ -6,7 +6,7 @@ subtitle: 'Use a custom email provider to send authentication messages'
The Send Email Hook runs before an email is sent and allows for flexibility around email sending. You can use this hook to configure a back-up email provider or add internationalization to your emails.
-## Email Sending Behavior
+## Email sending behavior
Email sending depends on two settings: Email Provider and Auth Hook status.
diff --git a/apps/docs/content/guides/auth/auth-mfa/phone.mdx b/apps/docs/content/guides/auth/auth-mfa/phone.mdx
index 62eb80f8fa9..e06b7e458cc 100644
--- a/apps/docs/content/guides/auth/auth-mfa/phone.mdx
+++ b/apps/docs/content/guides/auth/auth-mfa/phone.mdx
@@ -306,7 +306,7 @@ function AuthMFA() {
the background automatically and finally call the `onSuccess` callback, which
will show the authenticated `App` component on screen.
-### Security Configuration
+### Security configuration
Each code is valid for up to 5 minutes, after which a new one can be sent. Successive codes remain valid until expiry. When possible choose the longest code length acceptable to your use case, at a minimum of 6. This can be configured in the [Authentication Settings](/dashboard/project/_/settings/auth).
diff --git a/apps/docs/content/guides/auth/debugging/error-codes.mdx b/apps/docs/content/guides/auth/debugging/error-codes.mdx
index 92392b22fc0..06fca4a0ed3 100644
--- a/apps/docs/content/guides/auth/debugging/error-codes.mdx
+++ b/apps/docs/content/guides/auth/debugging/error-codes.mdx
@@ -5,11 +5,11 @@ description: 'Supabase Auth Error Codes'
subtitle: 'Learn about the Auth error codes and how to resolve them'
---
-## Auth Error Codes
+## Auth error codes
Supabase Auth can return various errors when using its API. This guide explains how to handle these errors effectively across different programming languages.
-## Error Types
+## Error types
Supabase Auth errors are generally categorized into two main types:
@@ -59,25 +59,26 @@ Errors originating from the server API classed as `AuthApiError` always have a `
-All errors originating from the `supabase.auth` namespace of the JavaScript client library will be wrapped by the `AuthError` class.
+All exceptions originating from the `supabase.auth` namespace of the Kotlin client library will be a subclass of `RestException`.
-Error objects are split in a few classes:
+Rest exceptions are split into a few classes:
-- `AuthApiError` -- errors which originate from the Supabase Auth API.
- - Use `isAuthApiError` instead of `instanceof` checks to see if an error you caught is of this type.
-- `CustomAuthError` -- errors which generally originate from state in the client library.
- - Use the `name` property on the error to identify the class of error received.
+- `AuthRestException` -- exceptions which originate from the Supabase Auth API and have a `errorCode` property that can be used to identify the error returned by the server.
+- `AuthWeakPasswordException` -- an `AuthRestException` which indicates that the password is too weak.
+- `AuthSessionMissingException` -- an `AuthRestException` which indicates that the session is missing, if the user was logged out or deleted.
-Errors originating from the server API classed as `AuthApiError` always have a `code` property that can be used to identify the error returned by the server. The `status` property is also present, encoding the HTTP status code received in the response.
+All instances and subclasses of a `AuthRestException` have a `errorCode` property that can be used to identify the error returned by the server.
-## HTTP Status Codes
+## HTTP status codes
Below are the most common HTTP status codes you might encounter, along with their meanings in the context of Supabase Auth:
+{/* supa-mdx-lint-disable Rule001HeadingCase */}
+
### [403 Forbidden](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403)
Sent out in rare situations where a certain Auth feature is not available for the user, and you as the developer are not checking a precondition whether that API is available for the user.
@@ -98,13 +99,15 @@ Indicate that the Auth server's service is degraded. Most often it points to iss
Sent out when a feature is not enabled on the Auth server, and you are trying to use an API which requires it.
-The following table provides a comprehensive list of error codes you may encounter when working with Supabase Auth. Each error code is associated with a specific issue and includes a description to help you understand and resolve the problem efficiently.
+{/* supa-mdx-lint-enable Rule001HeadingCase */}
-## Auth Error Codes Table
+## Auth error codes table
+
+The following table provides a comprehensive list of error codes you may encounter when working with Supabase Auth. Each error code is associated with a specific issue and includes a description to help you understand and resolve the problem efficiently.
-## Best Practices for Error Handling
+## Best practices for error handling
- Always use `error.code` and `error.name` to identify errors, not string matching on error messages.
- Avoid relying solely on HTTP status codes, as they may change unexpectedly.
diff --git a/apps/docs/content/guides/auth/native-mobile-deep-linking.mdx b/apps/docs/content/guides/auth/native-mobile-deep-linking.mdx
index d8ec66771b5..b1e1a6b41aa 100644
--- a/apps/docs/content/guides/auth/native-mobile-deep-linking.mdx
+++ b/apps/docs/content/guides/auth/native-mobile-deep-linking.mdx
@@ -11,7 +11,7 @@ Many Auth methods involve a redirect to your app. For example:
With Deep Linking, you can configure this redirect to open a specific page. This is necessary if, for example, you need to display a form for password reset, or to manually exchange a token hash.
-## Setting up Deep Linking
+## Setting up deep linking
-## Enabling Phone Login
+## Enabling phone login
Enable phone authentication on the [Auth Providers page](/dashboard/project/_/auth/providers) for hosted Supabase projects.
@@ -215,6 +215,15 @@ try await supabase.auth.updateUser(
)
```
+
+
+
+```kotlin
+supabase.auth.updateUser {
+ phone = "123456789"
+}
+```
+
diff --git a/apps/docs/content/guides/auth/redirect-urls.mdx b/apps/docs/content/guides/auth/redirect-urls.mdx
index 92b225af67e..9fe181bd856 100644
--- a/apps/docs/content/guides/auth/redirect-urls.mdx
+++ b/apps/docs/content/guides/auth/redirect-urls.mdx
@@ -100,7 +100,7 @@ For mobile applications you can use deep linking URIs. For example, for your `SI
Read more about deep linking and find code examples for different frameworks [here](/docs/guides/auth/native-mobile-deep-linking).
-## Error Handling
+## Error handling
When authentication fails, the user will still be redirected to the redirect URL provided. However, the error details will be returned as query fragments in the URL. You can parse these query fragments and show a custom error message to the user. For example:
diff --git a/apps/docs/content/guides/auth/server-side/advanced-guide.mdx b/apps/docs/content/guides/auth/server-side/advanced-guide.mdx
index 3b8b37fafff..6bd744baab0 100644
--- a/apps/docs/content/guides/auth/server-side/advanced-guide.mdx
+++ b/apps/docs/content/guides/auth/server-side/advanced-guide.mdx
@@ -38,6 +38,8 @@ To improve experience for your users, we recommend redirecting users to one spec
This is not necessary. Both the access token and refresh token are designed to be passed around to different components in your application. The browser-based side of your application needs access to the refresh token to properly maintain a browser session anyway.
+{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
+
### My server is getting invalid refresh token errors. What's going on?
It is likely that the refresh token sent from the browser to your server is stale. Make sure the `onAuthStateChange` listener callback is free of bugs and is registered relatively early in your application's lifetime
diff --git a/apps/docs/content/guides/auth/server-side/sveltekit.mdx b/apps/docs/content/guides/auth/server-side/sveltekit.mdx
index cb8b48079e1..bd41b4276c1 100644
--- a/apps/docs/content/guides/auth/server-side/sveltekit.mdx
+++ b/apps/docs/content/guides/auth/server-side/sveltekit.mdx
@@ -276,24 +276,24 @@ Set up a listener for Auth events on the client, to handle session refreshes and
```svelte src/routes/+layout.svelte
-
+{@render children()}
```
@@ -327,15 +327,15 @@ export const load: PageServerLoad = async ({ locals: { supabase } }) => {
```svelte src/routes/+page.svelte
-
```
diff --git a/apps/docs/content/guides/auth/sessions.mdx b/apps/docs/content/guides/auth/sessions.mdx
index 7d71f848912..3a219162e6a 100644
--- a/apps/docs/content/guides/auth/sessions.mdx
+++ b/apps/docs/content/guides/auth/sessions.mdx
@@ -119,7 +119,7 @@ When a user signs out, the sessions affected by the logout are removed from the
Note that sessions are not proactively terminated when their maximum lifetime (time-box) or inactivity timeout are reached. These sessions are cleaned up progressively 24 hours after reaching that status. This allows you to tweak the values or roll back changes without causing unintended user friction.
-### Can I use HTTP-Only cookies to store the access and refresh tokens?
+### Can I use HTTP-only cookies to store the access and refresh tokens?
This is possible, but only for apps that use the traditional server-only web app approach where all of the application logic is implemented on the server and it returns rendered HTML only.
diff --git a/apps/docs/content/guides/auth/third-party/aws-cognito.mdx b/apps/docs/content/guides/auth/third-party/aws-cognito.mdx
index 1fe4f487771..183d5f8f6e6 100644
--- a/apps/docs/content/guides/auth/third-party/aws-cognito.mdx
+++ b/apps/docs/content/guides/auth/third-party/aws-cognito.mdx
@@ -140,7 +140,7 @@ user_pool_id = ""
user_pool_region = ""
```
-## Use a Pre-Token Generation Trigger to assign the authenticated role
+## Use a pre-token generation trigger to assign the authenticated role
Your Supabase project inspects the `role` claim present in all JWTs sent to it, to assign the correct Postgres role when using the Data API, Storage or Realtime authorization.
diff --git a/apps/docs/content/guides/cron.mdx b/apps/docs/content/guides/cron.mdx
new file mode 100644
index 00000000000..84182b0dd14
--- /dev/null
+++ b/apps/docs/content/guides/cron.mdx
@@ -0,0 +1,34 @@
+---
+title: 'Cron'
+subtitle: 'Schedule Recurring Jobs with Cron Syntax in Postgres'
+---
+
+Supabase Cron is a Postgres Module that simplifies scheduling recurring Jobs with cron syntax and monitoring Job runs inside Postgres.
+
+Cron Jobs can be created via SQL or the Cron interface inside of Supabase Dashboard and can run anywhere from every second to once a year depending on your use case.
+
+Every Job can run SQL snippets or database functions with zero network latency or make an HTTP request, such as invoking a Supabase Edge Function, with ease.
+
+
+
+For best performance, we recommend no more than 8 Jobs run concurrently. Each Job should run no more than 10 minutes.
+
+
+
+## How does Cron work?
+
+Under the hood, Supabase Cron uses the [`pg_cron`](https://github.com/citusdata/pg_cron) Postgres database extension which is the scheduling and execution engine for your Jobs.
+
+
+
+`pg_cron` is not fully supported on Fly Postgres. Learn more about [Fly Postgres limitations](/docs/guides/platform/fly-postgres#limitations).
+
+
+
+The extension creates a `cron` schema in your database and all Jobs are stored on the `cron.job` table. Every Job's run and its status is recorded on the `cron.job_run_details` table.
+
+The Supabase Dashboard provides and interface for you to schedule Jobs and monitor Job runs. You can also do the same with SQL.
+
+## Resources
+
+- [`pg_cron` GitHub Repository](https://github.com/citusdata/pg_cron)
diff --git a/apps/docs/content/guides/cron/install.mdx b/apps/docs/content/guides/cron/install.mdx
new file mode 100644
index 00000000000..736b8870c28
--- /dev/null
+++ b/apps/docs/content/guides/cron/install.mdx
@@ -0,0 +1,44 @@
+---
+title: 'Install'
+---
+
+Install the Supabase Cron Postgres Module to begin scheduling recurring Jobs.
+
+
+
+
+1. Go to the [Cron Postgres Module](/dashboard/project/_/integrations/cron/overview) under Integrations in the Dashboard.
+2. Enable the `pg_cron` extension.
+
+
+
+
+```sql
+create extension pg_cron with schema pg_catalog;
+
+grant usage on schema cron to postgres;
+grant all privileges on all tables in schema cron to postgres;
+```
+
+
+
+
+## Uninstall
+
+Uninstall Supabase Cron by disabling the `pg_cron` extension:
+
+```sql
+drop extension if exists pg_cron;
+```
+
+
+
+Disabling the `pg_cron` extension will permanently delete all Jobs.
+
+
diff --git a/apps/docs/content/guides/cron/quickstart.mdx b/apps/docs/content/guides/cron/quickstart.mdx
new file mode 100644
index 00000000000..874644001a4
--- /dev/null
+++ b/apps/docs/content/guides/cron/quickstart.mdx
@@ -0,0 +1,337 @@
+---
+title: 'Quickstart'
+---
+
+
+
+Job names are case sensitive and cannot be edited once created.
+
+Attempting to create a second Job with the same name (and case) will overwrite the first Job.
+
+
+
+## Schedule a Job
+
+
+
+
+1. Go to the [Jobs](/dashboard/project/_/integrations/cron/jobs) section to schedule your first Job.
+2. Click on `Create job` button or navigate to the new Cron Job form [here](/dashboard/project/_/integrations/cron/jobs?dialog-shown=true).
+3. Name your Cron Job.
+4. Choose a schedule for your Job by inputting cron syntax (refer to the syntax chart in the form) or natural language.
+5. Input SQL snippet or select a Database function, HTTP request, or Supabase Edge Function.
+
+
+
+
+
+
+```sql
+-- Cron Job name cannot be edited
+select cron.schedule('permanent-cron-job-name', '30 seconds', 'CALL do_something()');
+```
+
+
+
+
+
+
+
+
+ ```
+ ┌───────────── min (0 - 59)
+ │ ┌────────────── hour (0 - 23)
+ │ │ ┌─────────────── day of month (1 - 31)
+ │ │ │ ┌──────────────── month (1 - 12)
+ │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to
+ │ │ │ │ │ Saturday, or use names; 7 is also Sunday)
+ │ │ │ │ │
+ │ │ │ │ │
+ * * * * *
+ ```
+
+ You can use [1-59] seconds (e.g. `30 seconds`) as the cron syntax to schedule sub-minute Jobs.
+
+
+
+
+
+
+
+
+You can input seconds for your Job schedule interval as long as you're on Postgres version 15.1.1.61 or later.
+
+
+
+## Edit a Job
+
+
+
+
+1. Go to the [Jobs](/dashboard/project/_/integrations/cron/jobs) section and find the Job you'd like to edit.
+2. Click on the three vertical dots menu on the right side of the Job and click `Edit cron job`.
+3. Make your changes and then click `Save cron job`.
+
+
+
+
+
+
+```sql
+select cron.alter_job(
+ job_id := (select jobid from cron.job where jobname = 'permanent-cron-job-name'),
+ schedule := '*/5 * * * *'
+);
+```
+
+Full options for the `cron.alter_job()` function are:
+
+```sql
+cron.alter_job(
+ job_id bigint,
+ schedule text default null,
+ command text default null,
+ database text default null,
+ username text default null,
+ active boolean default null
+)
+```
+
+It is also possible to modify a job by using the `cron.schedule()` function by inputting the same job name. This will replace the existing job via upsert.
+
+
+
+
+## Activate/Deactivate a Job
+
+
+
+
+1. Go to the [Jobs](/dashboard/project/_/integrations/cron/jobs) section and find the Job you'd like to unschedule.
+2. Toggle the `Active`/`Inactive` switch next to Job name.
+
+
+
+
+
+
+```sql
+-- Activate Job
+select cron.alter_job(
+ job_id := (select jobid from cron.job where jobname = 'permanent-cron-job-name'),
+ active := true
+);
+
+-- Deactivate Job
+select cron.alter_job(
+ job_id := (select jobid from cron.job where jobname = 'permanent-cron-job-name'),
+ active := false
+);
+```
+
+
+
+
+## Unschedule a Job
+
+
+
+
+1. Go to the [Jobs](/dashboard/project/_/integrations/cron/jobs) section and find the Job you'd like to delete.
+2. Click on the three vertical dots menu on the right side of the Job and click `Delete cron job`.
+3. Confirm deletion by entering the Job name.
+
+
+
+
+
+
+```sql
+select cron.unschedule('permanent-cron-job-name');
+```
+
+
+
+Unscheduling a Job will permanently delete the Job from `cron.job` table but its run history remain in `cron.job_run_details` table.
+
+
+
+
+
+
+## Inspecting Job Runs
+
+
+
+
+1. Go to the [Jobs](/dashboard/project/_/integrations/cron/jobs) section and find the Job you want to see the runs of.
+2. Click on the `History` button next to the Job name.
+
+
+
+
+
+
+```sql
+select
+ *
+from cron.job_run_details
+where jobid = (select jobid from cron.job where jobname = 'permanent-cron-job-name')
+order by start_time desc
+limit 10;
+```
+
+
+
+The records in the `cron.job_run_details` table are not cleaned up automatically. They are also not removed when jobs are unscheduled, which will take up disk space in your database.
+
+
+
+
+
+
+## Examples
+
+### Delete data every week
+
+{/* */}
+
+Delete old data every Saturday at 3:30AM (GMT):
+
+{/* */}
+
+```sql
+select cron.schedule (
+ 'saturday-cleanup', -- name of the cron job
+ '30 3 * * 6', -- Saturday at 3:30AM (GMT)
+ $$ delete from events where event_time < now() - interval '1 week' $$
+);
+```
+
+### Run a vacuum every day
+
+{/* */}
+
+Vacuum every day at 3:00AM (GMT):
+
+{/* */}
+
+```sql
+select cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM');
+```
+
+### Call a database function every 5 minutes
+
+Create a [`hello_world()`](/docs/guides/database/functions?language=sql#simple-functions) database function and then call it every 5 minutes:
+
+```sql
+select cron.schedule('call-db-function', '*/5 * * * *', 'SELECT hello_world()');
+```
+
+### Call a database stored procedure
+
+To use a stored procedure, you can call it like this:
+
+```sql
+select cron.schedule('call-db-procedure', '*/5 * * * *', 'CALL my_procedure()');
+```
+
+### Invoke Supabase Edge Function every 30 seconds
+
+Make a POST request to a Supabase Edge Function every 30 seconds:
+
+```sql
+select
+ cron.schedule(
+ 'invoke-function-every-half-minute',
+ '30 seconds',
+ $$
+ select
+ net.http_post(
+ url:='https://project-ref.supabase.co/functions/v1/function-name',
+ headers:=jsonb_build_object('Content-Type','application/json', 'Authorization', 'Bearer ' || 'YOUR_ANON_KEY'),
+ body:=jsonb_build_object('time', now() ),
+ timeout_milliseconds:=5000
+ ) as request_id;
+ $$
+ );
+```
+
+
+
+This requires the [`pg_net` extension](/docs/guides/database/extensions/pg_net) to be enabled.
+
+
+
+## Caution: Scheduling System Maintenance
+
+Be extremely careful when setting up Jobs for system maintenance tasks as they can have unintended consequences.
+
+For instance, scheduling a command to terminate idle connections with `pg_terminate_backend(pid)` can disrupt critical background processes like nightly backups. Often, there is an existing Postgres setting, such as `idle_session_timeout`, that can perform these common maintenance tasks without the risk.
+
+Reach out to [Supabase Support](https://supabase.com/support) if you're unsure if that applies to your use case.
diff --git a/apps/docs/content/guides/database/connecting-to-postgres.mdx b/apps/docs/content/guides/database/connecting-to-postgres.mdx
index dbf6406a713..a8e103f3451 100644
--- a/apps/docs/content/guides/database/connecting-to-postgres.mdx
+++ b/apps/docs/content/guides/database/connecting-to-postgres.mdx
@@ -1,89 +1,138 @@
---
-id: 'connecting-to-postgres'
-title: 'Connecting to your database'
-description: 'Explore the options for connecting to your Postgres database.'
-subtitle: 'Explore the options for connecting to your Postgres database.'
+title: 'Connect to your database'
+description: 'Connect to Postgres from your frontend, backend, or serverless environment'
+subtitle: 'Connect to Postgres from your frontend, backend, or serverless environment'
---
-Supabase provides several options for programmatically connecting to your Postgres database:
+## Quick summary
-1. The Data APIs
-1. Using one of the many [Client Libraries](/docs/reference)
-1. Direct connections using the built-in Postgres connection system
-1. Connection pooling for scalable connections
+How you connect to your database depends on where you're connecting from:
-## Data APIs
+- For frontend applications, use the [Data API](#data-apis-and-client-libraries)
+- For Postgres clients, use a connection string
+ - For persistent clients (for example, long-running servers or database GUIs) use the [direct connection string](#direct-connection) if your environment supports IPv6, and [Supavisor session mode](#supavisor-session-mode) if not
+ - For temporary clients (for example, serverless or edge functions) use [Supavisor transaction mode](#supavisor-transaction-mode)
-Supabase's Data APIs are the easiest way to get started if you are managing data (fetching, inserting, updating). We provide several types of API to suit your preferences:
+## Quickstarts
-- [REST](/docs/guides/api): interact with your database through a REST interface.
-- [GraphQL](/docs/guides/graphql/api): interact with your database through a GraphQL interface.
-- [Realtime](/docs/guides/realtime#realtime-api): listen to database changes over websockets.
+
-## Client libraries
+## Data APIs and client libraries
-Supabase offers [client libraries](/docs/reference) for popular programming languages. These libraries provide a convenient wrapper around the Data APIs, making it easier to interact with your database using your preferred language.
+The Data APIs allow you to interact with your database using REST or GraphQL requests. You can use these APIs to fetch and insert data from the frontend, as long as you have [RLS](/docs/guides/database/postgres/row-level-security) enabled.
-## Connecting to external libraries and tools
+- [REST](/docs/guides/api)
+- [GraphQL](/docs/guides/graphql/api)
-Beyond the [Supabase client-libraries](/docs/guides/api/rest/client-libs), Supabase provides three connection strings for direct database access, compatible with all postgres libraries, such as [Prisma](/docs/guides/database/prisma) and [Drizzle](/docs/guides/database/drizzle), as well as tools like [PSQL](/docs/guides/database/psql) and [pgAdmin](/docs/guides/database/pgadmin).
+For convenience, you can also use the Supabase client libraries, which wrap the Data APIs with a developer-friendly interface and automatically handle authentication:
-You can find these connection strings in your [Database Settings](https://supabase.com/dashboard/project/_/settings/database).
+- [JavaScript](/docs/reference/javascript)
+- [Flutter](/docs/reference/dart)
+- [Swift](/docs/reference/swift)
+- [Python](/docs/reference/python)
+- [C#](/docs/reference/csharp)
+- [Kotlin](/docs/reference/kotlin)
-### Direct connections:
+## Direct connection
-It connects directly to your Postgres instance. It is ideal for persistent servers, such as virtual machines (VMs) and long-lasting containers. Examples include AWS EC2 machines, Fly.io VMs, and DigitalOcean Droplets.
+The direct connection string connects directly to your Postgres instance. It is ideal for persistent servers, such as virtual machines (VMs) and long-lasting containers. Examples include AWS EC2 machines, Fly.io VMs, and DigitalOcean Droplets.
-Direct connections use IPv6 by default. If your environment doesn't support IPv6 or you're unsure but still want to use a direct connection, check out the [networking guide](/docs/guides/platform/ipv4-address#supabase-and-ipv6-compatibility) for more info.
+Direct connections use IPv6 by default. If your environment doesn't support IPv6, use [Supavisor session mode](#supavisor-session-mode) or get the [IPv4 addon](/docs/guides/platform/ipv4-address).
-```md
-// Example String
+The connection string looks like this:
+
+```
postgresql://postgres:[YOUR-PASSWORD]@db.apbkobhfnmcqqzqeeqss.supabase.co:5432/postgres
```
-You can find the direct connection string in the [Database settings](https://supabase.com/dashboard/project/_/settings/database) inside the dashboard:
+Get your project's direct string from the [Database Settings](/dashboard/project/_/settings/database) page:
1. Go to the `Settings` section.
2. Click `Database`.
-3. Under `Connection string`, make sure `Use connection pooling` is unchecked. Copy the URI.
+3. Under `Connection string`, make sure `Display connection pooler` is unchecked. Copy the URI.
-### Supavisor session mode (port 5432):
+## Supavisor session mode
-In Session mode, Supavisor acts as an IPv4 proxy. It allows developers in IPv4-only environments to access a direct-connection experience without needing the IPv4 add-on.
+The session mode connection string connects to your Postgres instance via a proxy. This is ideal for persistent servers when IPv4 is not supported.
-```md
-// Example String
+The connection string looks like this:
+
+```
postgres://postgres.apbkobhfnmcqqzqeeqss:[YOUR-PASSWORD]@aws-0-ca-central-1.pooler.supabase.com:5432/postgres
```
-### Transaction mode (port 6543):
+Get your project's session mode string from the [Database Settings](/dashboard/project/_/settings/database) page:
+
+1. Go to the `Settings` section.
+2. Click `Database`.
+3. Under `Connection string`, make sure `Display connection pooler` is checked and `Session mode` is selected. Copy the URI.
+
+## Supavisor transaction mode
+
+The transaction mode connection string connects to your Postgres instance via a proxy which serves as a connection pooler. This is deal for serverless or edge functions, which require many transient connections.
-Transaction mode does not support [prepared statements](https://postgresql.org/docs/current/sql-prepare.html). To avoid errors, [turn off prepared statements](https://github.com/orgs/supabase/discussions/28239) for your specific connection library.
+Transaction mode does not support [prepared statements](https://postgresql.org/docs/current/sql-prepare.html). To avoid errors, [turn off prepared statements](https://github.com/orgs/supabase/discussions/28239) for your connection library.
-Supavisor in transaction mode forms hot connections with the database and only allows clients to access them when a query is pending. It has amazing scaling capacity, and is best used with temporary servers, such as serverless/Edge Functions or auto-scaling servers.
+The connection string looks like this:
-```md
-// Example String
+```
postgres://postgres.apbkobhfnmcqqzqeeqss:[YOUR-PASSWORD]@aws-0-ca-central-1.pooler.supabase.com:6543/postgres
```
-## Connection pooling in-depth
+Get your project's transaction mode string from the [Database Settings](/dashboard/project/_/settings/database) page:
-### Application side poolers
+1. Go to the `Settings` section.
+2. Click `Database`.
+3. Under `Connection string`, make sure `Display connection pooler` is checked and `Transaction mode` is selected. Copy the URI.
+
+## More about connection pooling
+
+Connection pooling improves database performance by reusing existing connections between queries. This reduces the overhead of establishing connections and improves scalability.
+
+You can use an application-side pooler or a server-side pooler (Supabase automatically provides one called Supavisor), depending on whether your backend is persistent or serverless.
+
+### Application-side poolers
Application-side poolers are built into connection libraries and API servers, such as Prisma, SQLAlchemy, and PostgREST. They maintain several active connections with Postgres or a server-side pooler, reducing the overhead of establishing connections between queries. When deploying to static architecture, such as long-standing containers or VMs, application-side poolers are satisfactory on their own.
### Serverside poolers
-Postgres connections are like WebSocket, once established, they are preserved until the client (application server) disconnects. A server might only make a single 10 ms query, but needlessly reserve its database connection for seconds or longer.
+Postgres connections are like a WebSocket. Once established, they are preserved until the client (application server) disconnects. A server might only make a single 10 ms query, but needlessly reserve its database connection for seconds or longer.
Serverside-poolers, such as Supabase's [Supavisor](https://github.com/supabase/supavisor) in transaction mode, sit between clients and the database and can be thought of as load balancers for Postgres connections.
@@ -108,34 +157,6 @@ You can obtain your connection info and Server root certificate from your applic

-## Choosing a connection method
-
-- **Data APIs:** Best for operations supported by the Data APIs.
-- **Supavisor Pooler:**
- - **Transaction mode (port 6543):** Best for serverless/edge functions and rapidly auto-scaling servers
- - **Session mode (port 5432):** For long-lived servers, such as virtual machines (VM) and enduring containers (if IPv6 is unsupported)
-- **Direct Connections:** For long-lived servers, such as VMs and enduring containers (if IPv6 is supported or the IPv4 Add-On is enabled).
-
-## Quickstart connection guides
-
-
-
-If you'd like us to add a new quickstart guide, share your [feedback](https://supabase.com/dashboard/support/new), and we'll try to add it going forwards.
-
-
-
-### External libraries
-
-- [Prisma](/docs/guides/database/prisma)
-- [Drizzle](/docs/guides/database/drizzle)
-- [Postgres.js](/docs/guides/database/postgres-js)
-
-### External tools
-
-- [pgAdmin](/docs/guides/database/pgadmin)
-- [PSQL](/docs/guides/database/psql)
-- [DBeaver](/docs/guides/database/dbeaver)
-
## Resources
- [Connection management](/docs/guides/database/connection-management)
diff --git a/apps/docs/content/guides/database/extensions.mdx b/apps/docs/content/guides/database/extensions.mdx
index d5fb2834e26..3bdbb3db71f 100644
--- a/apps/docs/content/guides/database/extensions.mdx
+++ b/apps/docs/content/guides/database/extensions.mdx
@@ -54,7 +54,7 @@ In addition to the pre-configured extensions, you can also install your own SQL
-### Upgrade Extensions
+### Upgrade extensions
If a new version of an extension becomes available on Supabase, you need to initiate a software upgrade in the [Infrastructure Settings](https://supabase.com/dashboard/project/_/settings/infrastructure) to access it. Software upgrades can also be initiated by restarting your server in the [General Settings](https://supabase.com/dashboard/project/_/settings/general).
diff --git a/apps/docs/content/guides/database/extensions/pg_cron.mdx b/apps/docs/content/guides/database/extensions/pg_cron.mdx
index 6b934fbbe97..680a7680351 100644
--- a/apps/docs/content/guides/database/extensions/pg_cron.mdx
+++ b/apps/docs/content/guides/database/extensions/pg_cron.mdx
@@ -1,194 +1,7 @@
---
id: 'pg_cron'
-title: 'pg_cron: Job Scheduling'
-description: 'pgnet: a simple cron-based job scheduler for PostgreSQL that runs inside the database.'
+title: 'pg_cron: Schedule Recurring Jobs with Cron Syntax in Postgres'
+description: 'pg_cron: schedule recurring Jobs with cron syntax in Postgres.'
---
-The `pg_cron` extension is a simple cron-based job scheduler for PostgreSQL that runs inside the database.
-
-
-
-pg_cron is not fully supported on Fly Postgres. Read more about this [Fly Postgres limitation here](/docs/guides/platform/fly-postgres#limitations).
-
-
-
-## Usage
-
-### Enable the extension
-
-
-
-
-1. Go to the [Database](https://supabase.com/dashboard/project/_/database/tables) page in the Dashboard.
-2. Click on **Extensions** in the sidebar.
-3. Search for "pg_cron" and enable the extension.
-
-
-
-
-```sql
--- Example: enable the "pg_cron" extension
-create extension pg_cron with schema pg_catalog;
-
-grant usage on schema cron to postgres;
-grant all privileges on all tables in schema cron to postgres;
-
--- Example: disable the "pg_cron" extension
-drop extension if exists pg_cron;
-```
-
-
-
-
-### Syntax
-
-The schedule uses the standard cron syntax, in which \* means "run every time period", and a specific number means "but only at this time":
-
-```bash
- ┌───────────── min (0 - 59)
- │ ┌────────────── hour (0 - 23)
- │ │ ┌─────────────── day of month (1 - 31)
- │ │ │ ┌──────────────── month (1 - 12)
- │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to
- │ │ │ │ │ Saturday, or use names; 7 is also Sunday)
- │ │ │ │ │
- │ │ │ │ │
- * * * * *
-```
-
-You can use `[1-59] seconds` as the cron syntax to schedule sub-minute jobs. This is available on `pg_cron` v1.5.0+; upgrade your existing Supabase project to use this syntax.
-
-Head over to [crontab.guru](https://crontab.guru/) to validate your cron schedules.
-
-### Scheduling system maintenance
-
-Be extremely careful when setting up `pg_cron` jobs for system maintenance tasks as they can have unintended consequences. For instance, scheduling a command to terminate idle connections with `pg_terminate_backend(pid)` can disrupt critical background processes like nightly backups. Often, there is an existing Postgres setting e.g. `idle_session_timeout` that can perform these common maintenance tasks without the risk.
-
-Reach out to [Supabase Support](https://supabase.com/support) if you're unsure if that applies to your use case.
-
-## Examples
-
-### Delete data every week
-
-Delete old data every Saturday at 3:30am (GMT):
-
-```sql
-select cron.schedule (
- 'saturday-cleanup', -- name of the cron job
- '30 3 * * 6', -- Saturday at 3:30am (GMT)
- $$ delete from events where event_time < now() - interval '1 week' $$
-);
-```
-
-### Run a vacuum every day
-
-Vacuum every day at 3:00am (GMT):
-
-```sql
-select cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM');
-```
-
-### Call a database function every 5 minutes
-
-Create a [`hello_world()`](https://supabase.com/docs/guides/database/functions?language=sql#simple-functions) database function and then call it every 5 minutes:
-
-```sql
-select cron.schedule('call-db-function', '*/5 * * * *', 'SELECT hello_world()');
-```
-
-### Call a database stored procedure
-
-To use a stored procedure, you can call it like this:
-
-```sql
-select cron.schedule('call-db-procedure', '*/5 * * * *', 'CALL my_procedure()');
-```
-
-### Invoke Supabase Edge Function every 30 seconds
-
-
-
-This requires `pg_cron` v1.5.0+ and the [`pg_net` extension](/docs/guides/database/extensions/pgnet) to be enabled.
-
-
-
-Make a POST request to a Supabase Edge Function every 30 seconds:
-
-```sql
-select
- cron.schedule(
- 'invoke-function-every-half-minute',
- '30 seconds',
- $$
- select
- net.http_post(
- url:='https://project-ref.supabase.co/functions/v1/function-name',
- headers:=jsonb_build_object('Content-Type','application/json', 'Authorization', 'Bearer ' || 'YOUR_ANON_KEY'),
- body:=jsonb_build_object('time', now() ),
- timeout_milliseconds:=5000
- ) as request_id;
- $$
- );
-```
-
-### Edit a job
-
-Changes the frequency of a job called `'vacuum'` to once every 5 minutes.
-
-```sql
-select cron.alter_job(
- job_id := (select jobid from cron.job where jobname = 'vacuum'),
- schedule := '*/5 * * * *'
-);
-```
-
-Full options for the `cron.alter_job()` function are:
-
-```sql
-cron.alter_job(
- job_id bigint,
- schedule text default null,
- command text default null,
- database text default null,
- username text default null,
- active boolean default null
-)
-```
-
-It is also possible to modify a job by using the `cron.schedule()` function, with the same job name. This will replace the existing job, in the manner of an upsert.
-
-### Unschedule a job
-
-Unschedules a job called `'nightly-vacuum'`
-
-```sql
-select cron.unschedule('nightly-vacuum');
-```
-
-### Viewing previously ran jobs
-
-View the last ten jobs that have ran
-
-```sql
-select
- *
-from cron.job_run_details
-order by start_time desc
-limit 10;
-```
-
-
-
-The records in cron.job_run_details are not cleaned automatically which will take up disk space in your database.
-
-
-
-## Resources
-
-- [`pg_cron` GitHub Repository](https://github.com/citusdata/pg_cron)
+See the [Supabase Cron docs](/docs/guides/cron).
diff --git a/apps/docs/content/guides/database/extensions/pg_net.mdx b/apps/docs/content/guides/database/extensions/pg_net.mdx
index e0aac2027ec..eefacee9364 100644
--- a/apps/docs/content/guides/database/extensions/pg_net.mdx
+++ b/apps/docs/content/guides/database/extensions/pg_net.mdx
@@ -279,11 +279,11 @@ begin
) as request_id;
-- Optionally Log row data or other data for inspection in Supabase Dashboard's Postgres Logs
- -- (https://supabase.com/dashboard/project/_/logs/postgres-logs)
raise log 'Logging an entire row as JSON (%)', row_data_var;
- -- return the row data to inspect
+ -- return row data to inspect
return row_data_var;
+
-- Handle exceptions here if needed
exception
when others then
@@ -315,7 +315,7 @@ Supabase supports reconfiguring pg_net starting from v0.12.0+. For the latest re
-The extension is configured to execute up to 200 requests per second reliably. The response messages are stored for only 6 hours to prevent needless buildup. The default behavior can be modified by rewriting config variables.
+The extension is configured to reliably execute up to 200 requests per second. The response messages are stored for only 6 hours to prevent needless buildup. The default behavior can be modified by rewriting config variables.
### Get current settings
@@ -332,7 +332,7 @@ where "name" like 'pg_net%';
Change variables:
```sql
-alter role "postgres" set pg_net.ttl to '24 hour';
+alter role "postgres" set pg_net.ttl to '24 hours';
alter role "postgres" set pg_net.batch_size to 500;
```
@@ -416,7 +416,7 @@ with "selected_table_rows" as (
-- Converts all the rows into a JSONB array
jsonb_agg(to_jsonb(.*)) as JSON_payload
from
- -- Generally good practice to LIMIT the max amount of rows
+ -- good practice to LIMIT the max amount of rows
)
select
net.http_post(
@@ -426,7 +426,7 @@ select
FROM "selected_table_rows";
```
-More examples can be seen in the [Extension's GitHub page](https://github.com/supabase/pg_net/)
+More examples can be seen on the [Extension's GitHub page](https://github.com/supabase/pg_net/)
## Limitations
@@ -435,7 +435,7 @@ More examples can be seen in the [Extension's GitHub page](https://github.com/su
- Can only make POST requests with JSON data. No other data formats are supported
- Intended to handle at most 200 requests per second. Increasing the rate can introduce instability
- Does not have support for PATCH/PUT requests
-- Can only work with one database at a time in PostgreSQL. It defaults to the postgres database.
+- Can only work with one database at a time. It defaults to the postgres database.
## Resources
diff --git a/apps/docs/content/guides/database/extensions/rum.mdx b/apps/docs/content/guides/database/extensions/rum.mdx
index e6fbe850a61..c95943e0202 100644
--- a/apps/docs/content/guides/database/extensions/rum.mdx
+++ b/apps/docs/content/guides/database/extensions/rum.mdx
@@ -58,7 +58,7 @@ drop extension if exists rum;
### Syntax
-#### For type: tsvector
+#### For type: `tsvector`
To understand the following you may need first to see [Official PostgreSQL documentation on text
search](https://www.postgresql.org/docs/current/functions-textsearch.html)
@@ -116,7 +116,7 @@ SELECT id, d, d `<=>` '2016-05-16 14:21:25' FROM tsts WHERE t @@ 'wr&qh' ORDER B
(5 rows)
```
-#### For type: anyarray
+#### For type: `anyarray`
`rum_anyarray_ops`
diff --git a/apps/docs/content/guides/database/orioledb.mdx b/apps/docs/content/guides/database/orioledb.mdx
new file mode 100644
index 00000000000..ba8e3279502
--- /dev/null
+++ b/apps/docs/content/guides/database/orioledb.mdx
@@ -0,0 +1,137 @@
+---
+id: 'orioledb'
+title: 'OrioleDB Overview'
+description: "A storage extension for PostgreSQL which uses PostgreSQL's pluggable storage system"
+---
+
+The [OrioleDB](https://www.orioledb.com/) Postgres extension provides a drop-in replacement storage engine for the default heap storage method. It is designed to improve Postgres' scalability and performance.
+
+OrioleDB addresses PostgreSQL's scalability limitations by removing bottlenecks in the shared memory cache under high concurrency. It also optimizes write-ahead-log (WAL) insertion through row-level WAL logging. These changes lead to significant improvements in the industry standard TPC-C benchmark, which approximates a real-world transactional workload. The following benchmark was performed on a c7g.metal instance and shows OrioleDB's performance outperforming the default PostgreSQL heap method with a 3.3x speedup.
+
+
+
+
+
+OrioleDB is in active development and currently has [certain limitations](https://www.orioledb.com/docs/usage/getting-started#current-limitations). Currently, only B-tree indexes are supported, so features like pg_vector's HNSW indexes are not yet available. An Index Access Method bridge to unlock support for all index types used with heap storage is under active development. In the Supabase OrioleDB image the default storage method has been updated to use OrioleDB, granting better performance out of the box.
+
+
+
+## Concepts
+
+### Index-organized tables
+
+OrioleDB uses index-organized tables, where table data is stored in the index structure. This design eliminates the need for separate heap storage, reduces overhead and improves lookup performance for primary key queries.
+
+### No buffer mapping
+
+In-memory pages are connected to the storage pages using direct links. This allows OrioleDB to bypass PostgreSQL's shared buffer pool and eliminate the associated complexity and contention in buffer mapping.
+
+### Undo log
+
+Multi-Version Concurrency Control (MVCC) is implemented using an undo log. The undo log stores previous row versions and transaction information, which enables consistent reads while removing the need for table vacuuming completely.
+
+### Copy-on-write checkpoints
+
+OrioleDB implements copy-on-write checkpoints to persist data efficiently. This approach writes only modified data during a checkpoint, reducing the I/O overhead compared to traditional PostgreSQL checkpointing and allowing row-level WAL logging.
+
+## Usage
+
+### Creating OrioleDB project
+
+You can get started with OrioleDB by enabling the extension in your Supabase dashboard.
+To get started with OrioleDB you need to [create a new Supabase project](https://supabase.com/dashboard/new/_) and choose `OrioleDB Public Alpha` Postgres version.
+
+
+
+### Creating tables
+
+To create a table using the OrioleDB storage engine just execute the standard `CREATE TABLE` statement. By default it will create a table using OrioleDB storage engine. For example:
+
+```sql
+-- Create a table
+create table blog_post (
+ id int8 not null,
+ title text not null,
+ body text not null,
+ author text not null,
+ published_at timestamptz not null default CURRENT_TIMESTAMP,
+ views bigint not null,
+ primary key (id)
+);
+```
+
+### Creating indexes
+
+OrioleDB tables always have a primary key. If it wasn't defined explicitly, a hidden primary key is created using the `ctid` column.
+Additionally you can create secondary indexes.
+
+
+
+Currently, only B-tree indexes are supported, so features like pg_vector's HNSW indexes are not yet available.
+
+
+
+```sql
+-- Create an index
+create index blog_post_published_at on blog_post (published_at);
+
+create index blog_post_views on blog_post (views) where (views > 1000);
+```
+
+### Data manipulation
+
+You can query and modify data in OrioleDB tables using standard SQL statements, including `SELECT`, `INSERT`, `UPDATE`, `DELETE` and `INSERT ... ON CONFLICT`.
+
+```sql
+INSERT INTO blog_post (id, title, body, author, views)
+VALUES (1, 'Hello, World!', 'This is my first blog post.', 'John Doe', 1000);
+
+SELECT * FROM blog_post ORDER BY published_at DESC LIMIT 10;
+ id │ title │ body │ author │ published_at │ views
+────┼───────────────┼─────────────────────────────┼──────────┼───────────────────────────────┼───────
+ 1 │ Hello, World! │ This is my first blog post. │ John Doe │ 2024-11-15 12:04:18.756824+01 │ 1000
+```
+
+### Viewing query plans
+
+You can see the execution plan using standard `EXPLAIN` statement.
+
+```sql
+EXPLAIN SELECT * FROM blog_post ORDER BY published_at DESC LIMIT 10;
+ QUERY PLAN
+────────────────────────────────────────────────────────────────────────────────────────────────────────────
+ Limit (cost=0.15..1.67 rows=10 width=120)
+ -> Index Scan Backward using blog_post_published_at on blog_post (cost=0.15..48.95 rows=320 width=120)
+
+EXPLAIN SELECT * FROM blog_post WHERE id = 1;
+ QUERY PLAN
+──────────────────────────────────────────────────────────────────────────────────
+ Index Scan using blog_post_pkey on blog_post (cost=0.15..8.17 rows=1 width=120)
+ Index Cond: (id = 1)
+
+EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM blog_post ORDER BY published_at DESC LIMIT 10;
+ QUERY PLAN
+──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+ Limit (cost=0.15..1.67 rows=10 width=120) (actual time=0.052..0.054 rows=1 loops=1)
+ -> Index Scan Backward using blog_post_published_at on blog_post (cost=0.15..48.95 rows=320 width=120) (actual time=0.050..0.052 rows=1 loops=1)
+ Planning Time: 0.186 ms
+ Execution Time: 0.088 ms
+```
+
+## Resources
+
+- [Official OrioleDB documentation](https://www.orioledb.com/docs)
+- [OrioleDB GitHub repository](https://github.com/orioledb/orioledb)
diff --git a/apps/docs/content/guides/database/postgres/column-level-security.mdx b/apps/docs/content/guides/database/postgres/column-level-security.mdx
index 6ed691e326c..b5452a9d7a2 100644
--- a/apps/docs/content/guides/database/postgres/column-level-security.mdx
+++ b/apps/docs/content/guides/database/postgres/column-level-security.mdx
@@ -12,7 +12,7 @@ PostgreSQL's [Row Level Security (RLS)](https://www.postgresql.org/docs/current/
roles.
-## Policies at the Row Level
+## Policies at the row level
Policies in Row Level Security (RLS) are used to restrict access to rows in a table. Think of them like adding a `WHERE` clause to every query.
@@ -35,7 +35,7 @@ update
However, this gives the post owner full access to update the row, including all of the columns.
-## Privileges at the Column Level
+## Privileges at the column level
To restrict access to columns, you can use [Privileges](https://www.postgresql.org/docs/current/ddl-priv.html).
@@ -80,9 +80,9 @@ You can view and edit the privileges in the [Supabase Studio](https://supabase.c

-## Manage column privileges in Migrations
+## Manage column privileges in migrations
-While you can manage privileges directly from the Dashboard, as your project grows you may want to manage them in your migrations. Read about database migrations in the [Local Development](https://supabase.com/docs/guides/getting-started/local-development#database-migrations) guide.
+While you can manage privileges directly from the Dashboard, as your project grows you may want to manage them in your migrations. Read about database migrations in the [Local Development](https://supabase.com/docs/guides/deployment/database-migrations) guide.
diff --git a/apps/docs/content/guides/database/postgres/roles.mdx b/apps/docs/content/guides/database/postgres/roles.mdx
index b72ab8c1ad2..7a36f2761d7 100644
--- a/apps/docs/content/guides/database/postgres/roles.mdx
+++ b/apps/docs/content/guides/database/postgres/roles.mdx
@@ -46,7 +46,7 @@ When you created your project you were also asked to enter a password. This is a
Changing the password does not result in any downtime. All connected services, such as postgrest, pgbouncer, and other Supabase managed services, are automatically updated to use the latest password to ensure availability. However, if you have any external services connecting to the Supabase database using hardcoded username/password credentials, a manual update will be required.
-## Granting Permissions
+## Granting permissions
Roles can be granted various permissions on database objects using the `GRANT` command. Permissions include `SELECT`, `INSERT`, `UPDATE`, and `DELETE`. You can configure access to almost any object inside your database - including tables, views, functions, and triggers.
diff --git a/apps/docs/content/guides/database/postgres/timeouts.mdx b/apps/docs/content/guides/database/postgres/timeouts.mdx
index 8a735c9d7c1..0afd32c6cfc 100644
--- a/apps/docs/content/guides/database/postgres/timeouts.mdx
+++ b/apps/docs/content/guides/database/postgres/timeouts.mdx
@@ -3,9 +3,11 @@ title: Timeouts
subtitle: Extend database timeouts to execute longer transactions
---
-Requests made through the Supabase API and Dashboard have a timeout of 60 seconds. The database also has a global default timeout of 2 minutes.
+
-To execute longer transactions, connect to your database using [Supavisor](/docs/guides/database/connecting-to-postgres#connection-pooler) or the [direct connection string](/docs/guides/database/connecting-to-postgres#direct-connections), and change the timeout settings.
+Dashboard and [Client](/docs/guides/api/rest/client-libs) queries have a max-configurable timeout of 60 seconds. For longer transactions, use [Supavisor or direct connections](/docs/guides/database/connecting-to-postgres#quick-summary).
+
+
## Change Postgres timeout
@@ -124,9 +126,9 @@ language sql;
The Supabase Dashboard contains tools to help you identify timed-out and long-running queries.
-### Using the Log Explorer
+### Using the Logs Explorer
-Go to the [Log Explorer](/dashboard/project/_/logs/explorer), and run the following query to identify timed-out events (`statement timeout`) and queries that successfully run for longer than 10 seconds (`duration`).
+Go to the [Logs Explorer](/dashboard/project/_/logs/explorer), and run the following query to identify timed-out events (`statement timeout`) and queries that successfully run for longer than 10 seconds (`duration`).
```sql
select
diff --git a/apps/docs/content/guides/database/prisma.mdx b/apps/docs/content/guides/database/prisma.mdx
index af9727e9dfe..4b88a46403a 100644
--- a/apps/docs/content/guides/database/prisma.mdx
+++ b/apps/docs/content/guides/database/prisma.mdx
@@ -184,7 +184,7 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
-
+
If you have already modified your Supabase database, synchronize it with your migration file. Otherwise create new tables for your database
@@ -373,7 +373,7 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
-
+
Install the prisma client and generate its model
@@ -414,7 +414,7 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
-
+
Create a index.ts file and run it to test your connection
diff --git a/apps/docs/content/guides/database/prisma/prisma-troubleshooting.mdx b/apps/docs/content/guides/database/prisma/prisma-troubleshooting.mdx
index 851ea07ef6c..974528af322 100644
--- a/apps/docs/content/guides/database/prisma/prisma-troubleshooting.mdx
+++ b/apps/docs/content/guides/database/prisma/prisma-troubleshooting.mdx
@@ -27,6 +27,8 @@ connection_string.../postgres?KEY1=VALUE&KEY2=VALUE&KEY3=VALUE
# Errors
+{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
+
## ... prepared statement already exists
Supavisor in transaction mode (port 6543) does not support [prepared statements](https://www.postgresql.org/docs/current/sql-prepare.html), which Prisma will try to create in the background.
@@ -162,7 +164,7 @@ An alternative strategy to reference these tables is to duplicate values into Pr
Show/Hide Details
-
+
```sql table_in_public
-- Create the 'profiles' table in the 'public' schema
create table public.profiles (
diff --git a/apps/docs/content/guides/database/query-optimization.mdx b/apps/docs/content/guides/database/query-optimization.mdx
index d1e2d88690d..f34e8ebf2bd 100644
--- a/apps/docs/content/guides/database/query-optimization.mdx
+++ b/apps/docs/content/guides/database/query-optimization.mdx
@@ -34,7 +34,7 @@ limit 10;
In this query, there are several parts that indexes could likely help in optimizing the performance:
-### `where` Clause:
+### `where` clause:
The `where` clause filters rows based on certain conditions, and indexing the columns involved can improve this process:
@@ -47,7 +47,7 @@ create index idx_customers_sign_up_date on customers (sign_up_date);
create index idx_orders_status on orders (status);
```
-### `join` Columns
+### `join` columns
Indexes on the columns used for joining tables can help Postgres avoid scanning tables in their entirety when connecting tables.
@@ -58,7 +58,7 @@ Indexes on the columns used for joining tables can help Postgres avoid scanning
create index idx_orders_customer_id on orders (customer_id);
```
-### `order by` Clause
+### `order by` clause
Sorting can also be optimized by indexing:
diff --git a/apps/docs/content/guides/deployment/branching.mdx b/apps/docs/content/guides/deployment/branching.mdx
index aaeaf2cc543..0fe04bb1bff 100644
--- a/apps/docs/content/guides/deployment/branching.mdx
+++ b/apps/docs/content/guides/deployment/branching.mdx
@@ -339,7 +339,7 @@ You can create new migrations either [locally](#develop-locally) or [remotely](#
>
-The Supabase CLI provides two options: [manual migrations](https://supabase.com/docs/guides/cli/local-development#database-migrations) and [generated migrations](https://supabase.com/docs/guides/cli/local-development#diffing-changes) using Supabase's local studio and the `supabase db-diff` command. Let's use the latter and push the change to our Preview Branch:
+The Supabase CLI provides two options: [manual migrations](https://supabase.com/docs/guides/deployment/database-migrations) and [generated migrations](https://supabase.com/docs/guides/deployment/database-migrations#diffing-changes) using Supabase's local studio and the `supabase db-diff` command. Let's use the latter and push the change to our Preview Branch:
@@ -580,9 +580,9 @@ With the Supabase branching integration, you can sync the Git branch used by the
### Vercel
-
+
- The Vercel Integration for Supabase branching is under development. To express your interest, [join the discussion on GitHub discussions](https://github.com/orgs/supabase/discussions/18938).
+ The Vercel Integration for Supabase branching is working only with Supabase managed projects. There is currently no support for Vercel Marketplace managed resources, however the support is planned in the future.
@@ -598,10 +598,12 @@ For branching to work with Vercel, you also need the [Vercel GitHub integration]
Supabase automatically updates your Vercel project with the correct environment variables for the corresponding preview branches.
+The synchronization happens at the time of Pull Request being opened, not at the time of branch creation.
+As branching integration is tied to the Preview Deployments feature in Vercel, there are possible race conditions between Supabase setting correct variables, and Vercel running a deployment process. Because of that, Supabase is always automatically re-deploying the most recent deployment of the given pull request.
-### Netlify
+## Other Git providers
-A Netlify integration is under consideration. If you're interested in branching with Netlify, [join the GitHub discussion](https://github.com/orgs/supabase/discussions/18938).
+There are multiple alternative Git providers under consideration. If you're interested in branching for GitLab, Bitbucket, or some other provider, [join the GitHub discussion](https://github.com/orgs/supabase/discussions/18938).
## Alternatives to branching
diff --git a/apps/docs/content/guides/deployment/database-migrations.mdx b/apps/docs/content/guides/deployment/database-migrations.mdx
new file mode 100644
index 00000000000..11059b17bd8
--- /dev/null
+++ b/apps/docs/content/guides/deployment/database-migrations.mdx
@@ -0,0 +1,321 @@
+---
+id: 'database-migrations'
+title: 'Database Migrations'
+description: 'How to manage schema migrations for your Supabase project.'
+subtitle: 'How to manage schema migrations for your Supabase project.'
+video: 'https://www.youtube-nocookie.com/v/Kx5nHBmIxyQ'
+tocVideo: 'Kx5nHBmIxyQ'
+---
+
+Database migrations are SQL statements that create, update, or delete your existing database schemas. They are a common way of tracking changes to your database over time.
+
+## Schema migrations
+
+For this guide, we'll create a table called `employees` and see how we can make changes to it.
+
+You will need to [install](/docs/guides/local-development#quickstart) the Supabase CLI and start the local development stack.
+
+
+
+
+
+ To get started, generate a [new migration](/docs/reference/cli/supabase-migration-new) to store the SQL needed to create our `employees` table.
+
+
+
+
+```bash Terminal
+supabase migration new create_employees_table
+```
+
+
+
+
+
+
+
+
+
+
+ This creates a new migration file in supabase/migrations directory.
+
+ To that file, add the SQL to create this `employees` table.
+
+
+
+
+```sql supabase/migrations/_create_employees_table.sql
+create table if not exists employees (
+ id bigint primary key generated always as identity,
+ name text not null,
+ email text,
+ created_at timestamptz default now()
+);
+```
+
+
+
+
+
+
+
+
+
+
+ Run this migration to create the `employees` table.
+
+ Now you can visit your new `employees` table in the local Dashboard.
+
+
+
+
+```bash Terminal
+supabase migration up
+```
+
+
+
+
+
+
+
+
+
+
+ Next, modify your `employees` table by adding a column for `department`.
+
+
+
+
+```bash Terminal
+supabase migration new add_department_column
+```
+
+
+
+
+
+
+
+
+
+
+ To that new migration file, add the SQL to create a new `department` column.
+
+
+
+
+```sql supabase/migrations/_add_department_column.sql
+alter table if exists public.employees
+add department text default 'Hooli';
+```
+
+
+
+
+
+
+
+
+
+
+ Run this migration to update your existing `employees` table.
+
+
+
+
+```bash Terminal
+supabase migration up
+```
+
+
+
+
+
+
+Finally, you should see the `department` column added to your `employees` table in the local Dashboard.
+
+
+
+View the [complete code](https://github.com/supabase/supabase/tree/master/examples/database/employees) for this example on GitHub.
+
+
+
+### Seeding data
+
+Now that you are managing your database with migrations scripts, it would be great have some seed data to use every time you reset the database.
+
+
+
+
+
+ Create a seed script in supabase/seed.sql.
+
+ To that file, add the SQL to insert data into your `employees` table.
+
+
+
+
+```sql supabase/seed.sql
+insert into public.employees
+ (name)
+values
+ ('Erlich Bachman'),
+ ('Richard Hendricks'),
+ ('Monica Hall');
+```
+
+
+
+
+
+
+
+
+
+
+ Reset your database to reapply migrations and populate with seed data.
+
+
+
+
+```bash Terminal
+supabase db reset
+```
+
+
+
+
+
+
+You should now see the `employees` table, along with your seed data in the Dashboard! All of your database changes are captured in code, and you can reset to a known state at any time, complete with seed data.
+
+### Diffing changes
+
+This workflow is great if you know SQL and are comfortable creating tables and columns. If not, you can still use the Dashboard to create tables and columns, and then use the CLI to diff your changes and create migrations.
+
+
+
+
+
+ Create a new table called `cities`, with columns `id`, `name` and `population`.
+
+ Then generate a [schema diff](/docs/reference/cli/supabase-db-diff).
+
+
+
+
+```bash Terminal
+supabase db diff -f create_cities_table
+```
+
+
+
+
+
+
+
+
+
+
+ A new migration file is created for you.
+
+ Alternately, you can copy the table definitions directly from the Table Editor.
+
+
+
+
+```sql supabase/migrations/_create_cities_table.sql
+create table "public"."cities" (
+ "id" bigint primary key generated always as identity,
+ "name" text,
+ "population" bigint
+);
+```
+
+
+
+
+
+
+
+
+
+
+ Test your new migration file by resetting your local database.
+
+
+
+
+```bash Terminal
+supabase db reset
+```
+
+
+
+
+
+
+The last step is deploying these changes to a live Supabase project.
+
+## Deploy your project
+
+You've been developing your project locally, making changes to your tables via migrations. It's time to deploy your project to the Supabase Platform and start scaling up to millions of users!
+
+Head over to [Supabase](https://supabase.com/dashboard) and create a new project to deploy to.
+
+
+
+
+
+ [Login](/docs/reference/cli/supabase-login) to the Supabase CLI using an auto-generated Personal Access Token.
+
+
+
+
+```bash Terminal
+supabase login
+```
+
+
+
+
+
+
+
+
+
+
+ [Link](/docs/reference/cli/supabase-link) to your remote project by selecting from the on-screen prompt.
+
+
+
+
+```bash Terminal
+supabase link
+```
+
+
+
+
+
+
+
+
+
+
+ [Push](/docs/reference/cli/supabase-db-push) your migrations to the remote database.
+
+
+
+
+```bash Terminal
+supabase db push
+```
+
+
+
+
+
+
+Visiting your live project on [Supabase](https://supabase.com/dashboard/project/_), you'll see a new `employees` table, complete with the `department` column you added in the second migration above.
diff --git a/apps/docs/content/guides/deployment/maturity-model.mdx b/apps/docs/content/guides/deployment/maturity-model.mdx
index b224f6c04d9..6caddaaf96c 100644
--- a/apps/docs/content/guides/deployment/maturity-model.mdx
+++ b/apps/docs/content/guides/deployment/maturity-model.mdx
@@ -8,7 +8,7 @@ Supabase is great for building something very fast _and_ for scaling up. However
## Prototyping
-The Dashboard is a quick and easy tool for building applications while you are prototyping. That said, we strongly recommend using [Migrations](/docs/guides/getting-started/local-development#database-migrations) to manage your database changes. You can use our CLI to [capture any changes](/docs/reference/cli/supabase-db-diff) you have made on the Dashboard so that you can commit them a version control system, like git.
+The Dashboard is a quick and easy tool for building applications while you are prototyping. That said, we strongly recommend using [Migrations](/docs/guides/deployment/database-migrations) to manage your database changes. You can use our CLI to [capture any changes](/docs/reference/cli/supabase-db-diff) you have made on the Dashboard so that you can commit them a version control system, like git.
## Collaborating
@@ -16,7 +16,7 @@ As soon as you start collaborating with team members, all project changes should
Resources:
-- [Database migrations](/docs/guides/getting-started/local-development#database-migrations)
+- [Database migrations](/docs/guides/deployment/database-migrations)
- [Managing access on the Dashboard](/docs/guides/platform/access-control)
- [PGAudit for Postgres](/docs/guides/database/extensions/pgaudit)
@@ -33,7 +33,7 @@ Once your application is live, you should never change your database using the D
Resources:
-- [Database migrations](/docs/guides/getting-started/local-development#database-migrations)
+- [Database migrations](/docs/guides/deployment/database-migrations)
- [Managing access on the Dashboard](/docs/guides/platform/access-control)
- [PGAudit for Postgres](/docs/guides/database/extensions/pgaudit)
- [Managing environments](/docs/guides/cli/managing-environments)
diff --git a/apps/docs/content/guides/functions/background-tasks.mdx b/apps/docs/content/guides/functions/background-tasks.mdx
index fbc1f2aebf8..9480c2342cd 100644
--- a/apps/docs/content/guides/functions/background-tasks.mdx
+++ b/apps/docs/content/guides/functions/background-tasks.mdx
@@ -3,39 +3,59 @@ id: 'function-background-tasks'
title: 'Background Tasks'
description: 'How to run background tasks in an Edge Function outside of the request handler'
subtitle: 'How to run background tasks in an Edge Function outside of the request handler'
-tocVideo: 'rSKBTJxG9VA'
---
Edge Function instances can process background tasks outside of the request handler. Background tasks are useful for asynchronous operations like uploading a file to Storage, updating a database, or sending events to a logging service. You can respond to the request immediately and leave the task running in the background.
-### How long a background task can run
+### How it works
-A background task can run until the Edge Function instance hits its wall-clock limit or reaches CPU/Memory limit. Check [limits](/docs/guides/functions/limits) for current caps.
+You can use `EdgeRuntime.waitUntil(promise)` to explicitly mark background tasks. The Function instance continues to run until the promise provided to `waitUntil` completes.
+
+The maximum duration is capped based on the wall-clock, CPU, and memory limits. The Function will shutdown when it reaches one of these [limits](/docs/guides/functions/limits).
+
+You can listen to the `beforeunload` event handler to be notified when Function invocation is about to be shut down.
### Example
-Here's an example of defining a background task using a custom event.
+Here's an example of using `EdgeRuntime.waitUntil` to run a background task and using `beforeunload` event to be notified when the instance is about to be shut down.
```ts
-// Define a custom event type for the background task.
-class MyBackgroundTaskEvent extends Event {
- readonly taskPromise: Promise
-
- constructor(taskPromise: Promise) {
- super('myBackgroundTask')
- this.taskPromise = taskPromise
- }
+async function longRunningTask() {
+ // do work here
}
-globalThis.addEventListener('myBackgroundTask', async (event) => {
- const res = await (event as MyBackgroundTaskEvent).taskPromise
- console.log(await res.json())
+// Mark the longRunningTask's returned promise as a background task.
+// note: we are not using await because we don't want it to block.
+EdgeRuntime.waitUntil(longRunningTask())
+
+// Use beforeunload event handler to be notified when function is about to shutdown
+addEventListener('beforeunload', (ev) => {
+ console.log('Function will be shutdown due to', ev.detail?.reason)
+
+ // save state or log the current progress
})
+// Invoke the function using a HTTP request.
+// This will start the background task
Deno.serve(async (req) => {
- const fetchPromise = fetch('https://httpbin.org/json')
- const event = new MyBackgroundTaskEvent(fetchPromise)
- globalThis.dispatchEvent(event)
+ return new Response('ok')
+})
+```
+
+### Starting a background task in the request handler
+
+You can call `EdgeRuntime.waitUntil` in the request handler too. This will not block the request.
+
+```ts
+async function fetchAndLog(url: string) {
+ const response = await fetch(url)
+ console.log(response)
+}
+
+Deno.serve(async (req) => {
+ // this will not block the request,
+ // instead it will run in the background
+ EdgeRuntime.waitUntil(fetchAndLog('https://httpbin.org/json'))
return new Response('ok')
})
diff --git a/apps/docs/content/guides/functions/ephemeral-storage.mdx b/apps/docs/content/guides/functions/ephemeral-storage.mdx
new file mode 100644
index 00000000000..55bc58780ec
--- /dev/null
+++ b/apps/docs/content/guides/functions/ephemeral-storage.mdx
@@ -0,0 +1,54 @@
+---
+id: 'function-ephemeral-storage'
+title: 'Ephemeral Storage'
+description: 'Read and write from temporary directory'
+subtitle: 'Read and write from temporary directory'
+---
+
+Edge Functions provides ephemeral file storage. You can read and write files to the `/tmp` directory.
+
+Ephemeral storage will reset on each function invocation. This means the files you write during an invocation can only be read within the same invocation.
+
+### Use cases
+
+Here are some use cases where ephemeral storage can be useful:
+
+- Unzip an archive of CSVs and then add them as records to the DB
+- Custom image manipulation workflows (using [MagickWasm](https://supabase.com/docs/guides/functions/examples/image-manipulation))
+
+You can use [Background Tasks](https://supabase.com/docs/guides/functions/background-tasks) to handle slow file processing outside of a request.
+
+### How to use
+
+You can use [Deno File System APIs](https://docs.deno.com/api/deno/file-system) or the [`node:fs` module](https://docs.deno.com/api/node/fs/) to access the `/tmp` path.
+
+### Example
+
+Here is an example of how to write a user-uploaded zip file into temporary storage for further processing.
+
+```js
+Deno.serve(async (req) => {
+ if (req.headers.get('content-type') !== 'application/zip') {
+ return new Response('file must be a zip file', {
+ status: 400,
+ })
+ }
+
+ const uploadId = crypto.randomUUID()
+ await Deno.writeFile('/tmp/' + uploadId, req.body)
+
+ // do something with the written zip file
+
+ return new Response('ok')
+})
+```
+
+### Unavailable APIs
+
+Currently, the synchronous APIs (eg: `Deno.writeFileSync` or `Deno.mkdirSync`) for creating or writing files are not supported.
+
+You can use sync variations of read APIs (eg: `Deno.readFileSync`).
+
+### Limits
+
+In the hosted platform, a free project can write up to 256MB of data to ephemeral storage. A paid project can write up to 512MB.
diff --git a/apps/docs/content/guides/functions/examples/auth-send-email-hook-react-email-resend.mdx b/apps/docs/content/guides/functions/examples/auth-send-email-hook-react-email-resend.mdx
index 3eeaded1bed..f7c7ef537bf 100644
--- a/apps/docs/content/guides/functions/examples/auth-send-email-hook-react-email-resend.mdx
+++ b/apps/docs/content/guides/functions/examples/auth-send-email-hook-react-email-resend.mdx
@@ -114,7 +114,7 @@ Deno.serve(async (req) => {
})
```
-### 3. Create React Email Templates
+### 3. Create React Email templates
Create a new folder `_templates` and create a new file `magic-link.tsx` with the following code:
@@ -253,7 +253,7 @@ const code = {
-You can find a selection of React Email templates in the [React Email Eamples](https://react.email/examples).
+You can find a selection of React Email templates in the [React Email Examples](https://react.email/examples).
@@ -296,7 +296,7 @@ supabase secrets set --env-file supabase/functions/.env
That's it, now your Supabase Edge Function will be triggered anytime an Auth Email needs to be send to the user!
-## More Resources
+## More resources
- [Send Email Hooks](/docs/guides/auth/auth-hooks/send-email-hook)
- [Auth Hooks](/docs/guides/auth/auth-hooks)
diff --git a/apps/docs/content/guides/functions/examples/discord-bot.mdx b/apps/docs/content/guides/functions/examples/discord-bot.mdx
index bfe4a4e5114..48b0481bbc3 100644
--- a/apps/docs/content/guides/functions/examples/discord-bot.mdx
+++ b/apps/docs/content/guides/functions/examples/discord-bot.mdx
@@ -138,7 +138,7 @@ function hexToUint8Array(hex: string) {
}
```
-## Deploy the Slash Command handler
+## Deploy the slash command handler
```bash
supabase functions deploy discord-bot --no-verify-jwt
@@ -154,7 +154,7 @@ Navigate to your Function details in the Supabase Dashboard to get your Endpoint
The application is now ready. Let's proceed to the next section to install it.
-## Install the Slash Command on your Discord server
+## Install the slash command on your Discord server
So to use the `hello` Slash Command, we need to install our Greeter application on our Discord server. Here are the steps:
diff --git a/apps/docs/content/guides/functions/examples/push-notifications.mdx b/apps/docs/content/guides/functions/examples/push-notifications.mdx
index b59ad8879a9..994c7e4267d 100644
--- a/apps/docs/content/guides/functions/examples/push-notifications.mdx
+++ b/apps/docs/content/guides/functions/examples/push-notifications.mdx
@@ -18,14 +18,14 @@ Push notifications are an important part of any mobile app. They allow you to se
Find the example code on [GitHub](https://github.com/supabase/supabase/blob/master/examples/user-management/expo-push-notifications/).
- ## Supabase Setup
+ ## Supabase setup
- [Create a new Supabase project](https://database.new).
- Link your project: `supabase link --project-ref your-supabase-project-ref`
- Start supabase locally: `supabase start`
- Push up the schema: `supabase db push` (schema is defined in [supabase/migrations](https://github.com/supabase/supabase/blob/master/examples/user-management/expo-push-notifications/supabase/migrations/))
- ## Expo Setup
+ ## Expo setup
To utilize Expo's push notification service, you must configure your app by installing a set of libraries, implementing functions to handle notifications, and setting up credentials for Android and iOS. Follow the official [Expo Push Notifications Setup Guide](https://docs.expo.dev/push-notifications/push-notifications-setup/) to get the credentials for Android and iOS. This project uses [Expo's EAS build](https://docs.expo.dev/build/introduction/) service to simplify this part.
@@ -126,7 +126,7 @@ Push notifications are an important part of any mobile app. They allow you to se
This guide will show you how to send push notifications to your app when a new row is inserted into a table using FCM, Supabase Edge Functions, and database web hooks.
- ## Supabase Setup
+ ## Supabase setup
We will create two tables. One to store the user's FCM token and a `notifications` table. The edge function will be triggered when a new row is inserted into the `notifications` table and sends a push notification to the user.
@@ -258,7 +258,7 @@ Push notifications are an important part of any mobile app. They allow you to se
}
```
- ## FCM Setup
+ ## FCM setup
1. Follow the official [FCM Setup Guide](https://firebase.google.com/docs/cloud-messaging) to set up FCM for your client side application.
1. Generate a new service account private key from the Firebase console `Project Settings > Service Accounts > Generate new private key`.
diff --git a/apps/docs/content/guides/functions/examples/semantic-search.mdx b/apps/docs/content/guides/functions/examples/semantic-search.mdx
index b42077dd395..7534d6bafae 100644
--- a/apps/docs/content/guides/functions/examples/semantic-search.mdx
+++ b/apps/docs/content/guides/functions/examples/semantic-search.mdx
@@ -61,7 +61,7 @@ Deno.serve(async (req) => {
})
```
-## Create a Postgres Function and RPC
+## Create a Database Function and RPC
With the embeddings now stored in your Postgres database table, you can query them from Supabase Edge Functions by utilizing [Remote Procedure Calls (RPC)](/docs/guides/database/functions?language=js).
diff --git a/apps/docs/content/guides/functions/examples/sentry-monitoring.mdx b/apps/docs/content/guides/functions/examples/sentry-monitoring.mdx
index ec522e0a892..29bf2516193 100644
--- a/apps/docs/content/guides/functions/examples/sentry-monitoring.mdx
+++ b/apps/docs/content/guides/functions/examples/sentry-monitoring.mdx
@@ -79,7 +79,7 @@ supabase functions deploy sentryfied --no-verify-jwt
Find the complete example on [GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/sentryfied/index.ts).
-## Working With Scopes
+## Working with scopes
Sentry Deno SDK currently do not support `Deno.serve` instrumentation, which means that there is no scope separation between requests.
Because of that, when the Edge Functions runtime is reused between multiple requests, all globally captured breadcrumbs and contextual data
diff --git a/apps/docs/content/guides/functions/import-maps.mdx b/apps/docs/content/guides/functions/import-maps.mdx
index 15e7bfdc9ab..176aa73d4f2 100644
--- a/apps/docs/content/guides/functions/import-maps.mdx
+++ b/apps/docs/content/guides/functions/import-maps.mdx
@@ -12,7 +12,7 @@ Developing with Edge Functions is similar to developing with Node.js, but with a
There are two ways to manage your dependencies in Supabase Edge Functions:
-### Using deno.json (Recommended)
+### Using deno.json (recommended)
@@ -50,7 +50,7 @@ The recommended file structure when using `deno.json`:
└── config.toml
```
-### Using Import Maps (Legacy)
+### Using import maps (legacy)
Import Maps are a legacy way to manage dependencies, similar to a `package.json` file. While still supported, we recommend using `deno.json`. If both exist, `deno.json` takes precedence.
@@ -112,7 +112,7 @@ Supabase Edge Functions support several ways to import dependencies:
- Built-in [Node APIs](https://docs.deno.com/runtime/manual/node/compatibility)
- Third party modules published to [JSR](https://jsr.io/) or [deno.land/x](https://deno.land/x)
-### NPM Modules
+### NPM modules
You can import npm modules using the `npm:` specifier:
@@ -120,7 +120,7 @@ You can import npm modules using the `npm:` specifier:
import { createClient } from 'npm:@supabase/supabase-js@2'
```
-### Node.js Built-ins
+### Node.js built-ins
For Node.js built-in APIs, use the `node:` specifier:
@@ -130,7 +130,7 @@ import process from 'node:process'
Learn more about npm specifiers and Node built-in APIs in [Deno's documentation](https://docs.deno.com/runtime/manual/node/npm_specifiers).
-### Importing from Private Registries
+### Importing from private registries
diff --git a/apps/docs/content/guides/functions/limits.mdx b/apps/docs/content/guides/functions/limits.mdx
index c21f46009fd..9a41065188b 100644
--- a/apps/docs/content/guides/functions/limits.mdx
+++ b/apps/docs/content/guides/functions/limits.mdx
@@ -8,10 +8,13 @@ subtitle: "Limits applied Edge Functions in Supabase's hosted platform."
## Runtime limits
- Maximum Memory: 256MB
-- Maximum Duration (Wall clock limit): 400s (this is the duration an Edge Function worker will stay active. During this period, a worker can serve multiple requests)
-- Maximum CPU Time: 2s
-- Request idle timeout: 150s (if an Edge Function doesn't send a response before the timeout, 504 Gateway Timeout will be returned)
-- Maximum Function Size (after bundling via CLI): 10MB
+- Maximum Duration (Wall clock limit):
+ This is the duration an Edge Function worker will stay active. During this period, a worker can serve multiple requests or process background tasks.
+ - Free plan: 150s
+ - Paid plans: 400s
+- Maximum CPU Time: 2s (Amount of actual time spent on the CPU per request - does not include async I/O.)
+- Request idle timeout: 150s (If an Edge Function doesn't send a response before the timeout, 504 Gateway Timeout will be returned)
+- Maximum Function Size: 20MB (After bundling using CLI)
- Maximum log message length: 10,000 characters
- Log event threshold: 100 events per 10 seconds
@@ -19,6 +22,5 @@ subtitle: "Limits applied Edge Functions in Supabase's hosted platform."
- Outgoing connections to ports `25` and `587` are not allowed.
- Serving of HTML content is only supported with [custom domains](/docs/reference/cli/supabase-domains) (Otherwise `GET` requests that return `text/html` will be rewritten to `text/plain`).
-- Deno and Node file system APIs are not available.
- Web Worker API (or Node `vm` API) are not available.
- Node Libraries that require multithreading are not supported. Examples: [libvips](https://github.com/libvips/libvips), [sharp](https://github.com/lovell/sharp).
diff --git a/apps/docs/content/guides/functions/logging.mdx b/apps/docs/content/guides/functions/logging.mdx
index 4f0e66879cf..62a5cc3cd70 100644
--- a/apps/docs/content/guides/functions/logging.mdx
+++ b/apps/docs/content/guides/functions/logging.mdx
@@ -61,9 +61,9 @@ Deno.serve(async (req) => {
})
```
-## Logging Tips
+## Logging tips
-### Logging Request Headers
+### Logging request headers
When debugging Edge Functions, a common mistake is to try to log headers to the developer console via code like this:
@@ -88,7 +88,7 @@ The reason behind this behavior is that [Headers](https://developer.mozilla.org/
However, `Headers` objects are iterable. You can utilize this feature to craft a couple of succinct one-liners for debugging and printing headers.
-### Convert headers into an object with Object.fromEntries:
+### Convert headers into an object with `Object.fromEntries`:
You can use `Object.fromEntries` which is a call to convert the headers into an object:
diff --git a/apps/docs/content/guides/functions/routing.mdx b/apps/docs/content/guides/functions/routing.mdx
index f13eb21eeed..2944dacf500 100644
--- a/apps/docs/content/guides/functions/routing.mdx
+++ b/apps/docs/content/guides/functions/routing.mdx
@@ -15,7 +15,7 @@ To combine multiple endpoints into a single Edge Function, you can use web appli
Let's dive into some examples.
-## Routing with Frameworks
+## Routing with frameworks
Here's a simple hello world example using some popular web frameworks.
@@ -158,7 +158,7 @@ curl --request POST 'https://.supabase.co/functions/v1/hello-world'
We should see a response printing `Hello Foo!`.
-## Using Route Parameters
+## Using route parameters
We can use route parameters to capture values at specific URL segments (eg: `/tasks/:taskId/notes/:noteId`).
@@ -415,7 +415,7 @@ Deno.serve(async (req) => {
-## URL Patterns API
+## URL patterns API
If you prefer not to use a web framework, you can directly use [URLPattern API](https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API) within your Edge Functions to implement routing.
This is ideal for small apps with only couple of routes and you want to have a custom matching algorithm.
diff --git a/apps/docs/content/guides/functions/schedule-functions.mdx b/apps/docs/content/guides/functions/schedule-functions.mdx
index 1dd5fb88ed2..f0d64f319c6 100644
--- a/apps/docs/content/guides/functions/schedule-functions.mdx
+++ b/apps/docs/content/guides/functions/schedule-functions.mdx
@@ -13,7 +13,7 @@ description: 'Schedule Edge Functions with pg_cron.'
>
-The hosted Supabase Platform supports the [`pg_cron` extension](/docs/guides/database/extensions/pgcron), a simple cron-based job scheduler for PostgreSQL that runs inside the database.
+The hosted Supabase Platform supports the [`pg_cron` extension](/docs/guides/database/extensions/pgcron), a recurring job scheduler in Postgres.
In combination with the [`pg_net` extension](/docs/guides/database/extensions/pgnet), this allows us to invoke Edge Functions periodically on a set schedule.
diff --git a/apps/docs/content/guides/functions/status-codes.mdx b/apps/docs/content/guides/functions/status-codes.mdx
index 29f7a4307f6..5925a2ad3bb 100644
--- a/apps/docs/content/guides/functions/status-codes.mdx
+++ b/apps/docs/content/guides/functions/status-codes.mdx
@@ -5,6 +5,8 @@ description: 'Edge Functions can return following status codes.'
subtitle: 'Edge Functions can return following status codes.'
---
+{/* supa-mdx-lint-disable Rule001HeadingCase */}
+
## 2XX Success
A successful Edge Function Response
diff --git a/apps/docs/content/guides/functions/troubleshooting.mdx b/apps/docs/content/guides/functions/troubleshooting.mdx
index cdeddcbe9c6..2d69c1e0867 100644
--- a/apps/docs/content/guides/functions/troubleshooting.mdx
+++ b/apps/docs/content/guides/functions/troubleshooting.mdx
@@ -30,6 +30,8 @@ If your Edge Function takes too long to respond or times out:
- If the boot times are similar, it’s likely an issue with your function’s code, such as a large dependency, a slow API call, or a complex computation. You can try to optimize your code, reduce the size of your dependencies, or use caching techniques to improve the performance of your function.
- If only some of the `booted` events are slow, find the affected `region` in the metadata and submit a support request via the "Help" button at the top.
+{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
+
### Receiving 546 Error Response
The 546 error response might occur because:
@@ -47,7 +49,7 @@ The 546 error response might occur because:
## Advanced techniques
-### Monitoring Edge Function Resource Usage
+### Monitoring Edge Function resource usage
To determine how much memory and CPU your Edge Function consumes, follow these steps:
@@ -62,7 +64,7 @@ To determine how much memory and CPU your Edge Function consumes, follow these s
resources.
-### Understanding CPU soft and hard Limits
+### Understanding CPU soft and hard limits
An isolate is like a worker that can handle multiple requests for a function. It works until a time limit of 400 seconds is reached. Now, there are two types of limits for the CPU.
@@ -89,7 +91,7 @@ When analyzing dependencies for your Supabase Edge Functions, it's essential to
By selectively importing only the required submodules, you can effectively reduce the size of your function's dependencies and optimize its performance.
Before finalizing your imports, ensure to review both Deno and NPM dependencies, checking for any unnecessary or redundant dependencies that can be removed. Additionally, check for outdated dependencies and update to the latest versions if possible.
-#### Deno Dependencies
+#### Deno dependencies
Run `deno info`, providing the path to your input map if you use one.
Review the dependencies listed in the output. Pay attention to any significantly large dependencies, as they can contribute to increased bundle size and potential boot time issues.
@@ -99,7 +101,7 @@ Examine if there are any unnecessary or redundant dependencies that can be remov
deno info --import-map=/path/to/import_map.json /path/to/function/index.ts
```
-#### NPM Dependencies
+#### NPM dependencies
Additionally, if you utilize NPM modules in your Edge Functions, it's crucial to be mindful of their size and impact on the overall bundle size. While importing NPM modules, consider using the notation `import { submodule } from 'npm:package/submodule'` to selectively import specific submodules rather than importing the entire package. This approach can help minimize unnecessary overhead and streamline the execution of your function.
diff --git a/apps/docs/content/guides/functions/websockets.mdx b/apps/docs/content/guides/functions/websockets.mdx
new file mode 100644
index 00000000000..0c0c82201e8
--- /dev/null
+++ b/apps/docs/content/guides/functions/websockets.mdx
@@ -0,0 +1,236 @@
+---
+id: 'function-websockets'
+title: 'Handling WebSockets'
+description: 'How to handle WebSocket connections in Edge Functions'
+subtitle: 'How to handle WebSocket connections in Edge Functions'
+---
+
+Edge Functions supports hosting WebSocket servers that can facilitate bi-directional communications with browser clients.
+
+You can also establish outgoing WebSocket client connections to another server from Edge Functions (e.g., [OpenAI Realtime API](https://platform.openai.com/docs/guides/realtime/overview)). You can find an example OpenAI Realtime Relay Server implementation on the [supabase-community GitHub account](https://github.com/supabase-community/openai-realtime-console?tab=readme-ov-file#using-supabase-edge-functions-as-a-relay-server).
+
+### Writing a WebSocket server
+
+Here are some basic examples of setting up WebSocket servers using Deno and Node.js APIs.
+
+
+
+```ts
+ Deno.serve(req => {
+ const upgrade = req.headers.get("upgrade") || "";
+
+ if (upgrade.toLowerCase() != "websocket") {
+ return new Response("request isn't trying to upgrade to websocket.", { status: 400 });
+ }
+
+ const { socket, response } = Deno.upgradeWebSocket(req);
+
+ socket.onopen = () => console.log("socket opened");
+ socket.onmessage = (e) => {
+ console.log("socket message:", e.data);
+ socket.send(new Date().toString());
+ };
+
+ socket.onerror = e => console.log("socket errored:", e.message);
+ socket.onclose = () => console.log("socket closed");
+
+ return response;
+
+});
+
+````
+
+
+
+```ts
+import { createServer } from "node:http";
+import { WebSocketServer } from "npm:ws";
+
+const server = createServer();
+// Since we manually created the HTTP server,
+// turn on the noServer mode.
+const wss = new WebSocketServer({ noServer: true });
+
+wss.on("connection", ws => {
+ console.log("socket opened");
+ ws.on("message", (data /** Buffer */, isBinary /** bool */) => {
+ if (isBinary) {
+ console.log("socket message:", data);
+ } else {
+ console.log("socket message:", data.toString());
+ }
+
+ ws.send(new Date().toString());
+ });
+
+ ws.on("error", err => {
+ console.log("socket errored:", err.message);
+ });
+
+ ws.on("close", () => console.log("socket closed"));
+});
+
+server.on("upgrade", (req, socket, head) => {
+ wss.handleUpgrade(req, socket, head, ws => {
+ wss.emit("connection", ws, req);
+ });
+});
+
+server.listen(8080);
+````
+
+
+
+
+### Outbound WebSockets
+
+You can also establish an outbound WebSocket connection to another server from an Edge Function.
+
+Combining it with incoming WebSocket servers, it's possible to use Edge Functions as a WebSocket proxy, for example as a [relay server](https://github.com/supabase-community/openai-realtime-console?tab=readme-ov-file#using-supabase-edge-functions-as-a-relay-server) for the [OpenAI Realtime API](https://platform.openai.com/docs/guides/realtime/overview).
+
+<$CodeSample
+external={true}
+org="supabase-community"
+repo="openai-realtime-console"
+commit="0f93657a71670704fbf77c48cf54d6c9eb956698"
+path="/supabase/functions/relay/index.ts"
+meta="supabase/functions/relay/index.ts"
+lines={[[1, 3], [5, -1]]}
+/>
+
+### Authentication
+
+WebSocket browser clients don't have the option to send custom headers. Because of this, Edge Functions won't be able to perform the usual authorization header check to verify the JWT.
+
+You can skip the default authorization header checks by explicitly providing `--no-verify-jwt` when serving and deploying functions.
+
+To authenticate the user making WebSocket requests, you can pass the JWT in URL query params or via a custom protocol.
+
+
+
+```ts
+ import { createClient } from "jsr:@supabase/supabase-js@2";
+
+const supabase = createClient(
+Deno.env.get("SUPABASE_URL"),
+Deno.env.get("SUPABASE_SERVICE_ROLE_KEY"),
+);
+Deno.serve(req => {
+const upgrade = req.headers.get("upgrade") || "";
+
+ if (upgrade.toLowerCase() != "websocket") {
+ return new Response("request isn't trying to upgrade to websocket.", { status: 400 });
+ }
+
+// Please be aware query params may be logged in some logging systems.
+const url = new URL(req.url);
+const jwt = url.searchParams.get("jwt");
+if (!jwt) {
+console.error("Auth token not provided");
+return new Response("Auth token not provided", { status: 403 });
+}
+const { error, data } = await supabase.auth.getUser(jwt);
+if (error) {
+console.error(error);
+return new Response("Invalid token provided", { status: 403 });
+}
+if (!data.user) {
+console.error("user is not authenticated");
+return new Response("User is not authenticated", { status: 403 });
+}
+
+ const { socket, response } = Deno.upgradeWebSocket(req);
+
+ socket.onopen = () => console.log("socket opened");
+ socket.onmessage = (e) => {
+ console.log("socket message:", e.data);
+ socket.send(new Date().toString());
+ };
+
+ socket.onerror = e => console.log("socket errored:", e.message);
+ socket.onclose = () => console.log("socket closed");
+
+ return response;
+
+});
+
+````
+
+
+```ts
+ import { createClient } from "jsr:@supabase/supabase-js@2";
+
+const supabase = createClient(
+ Deno.env.get("SUPABASE_URL"),
+ Deno.env.get("SUPABASE_SERVICE_ROLE_KEY"),
+);
+ Deno.serve(req => {
+ const upgrade = req.headers.get("upgrade") || "";
+
+ if (upgrade.toLowerCase() != "websocket") {
+ return new Response("request isn't trying to upgrade to websocket.", { status: 400 });
+ }
+
+ // Sec-WebScoket-Protocol may return multiple protocol values `jwt-TOKEN, value1, value 2`
+ const customProtocols = (req.headers.get("Sec-WebSocket-Protocol") ?? '').split(',').map(p => p.trim())
+ const jwt = customProtocols.find(p => p.startsWith('jwt')).replace('jwt-', '')
+ if (!jwt) {
+ console.error("Auth token not provided");
+ return new Response("Auth token not provided", { status: 403 });
+ }
+ const { error, data } = await supabase.auth.getUser(jwt);
+ if (error) {
+ console.error(error);
+ return new Response("Invalid token provided", { status: 403 });
+ }
+ if (!data.user) {
+ console.error("user is not authenticated");
+ return new Response("User is not authenticated", { status: 403 });
+ }
+
+ const { socket, response } = Deno.upgradeWebSocket(req);
+
+ socket.onopen = () => console.log("socket opened");
+ socket.onmessage = (e) => {
+ console.log("socket message:", e.data);
+ socket.send(new Date().toString());
+ };
+
+ socket.onerror = e => console.log("socket errored:", e.message);
+ socket.onclose = () => console.log("socket closed");
+
+ return response;
+ });
+````
+
+
+
+
+### Limits
+
+The maximum duration is capped based on the wall-clock, CPU, and memory limits. The Function will shutdown when it reaches one of these [limits](/docs/guides/functions/limits).
+
+### Testing WebSockets locally
+
+When testing Edge Functions locally with Supabase CLI, the instances are terminated automatically after a request is completed. This will prevent keeping WebSocket connections open.
+
+To prevent that, you can update the `supabase/config.toml` with the following settings:
+
+```toml
+[edge_runtime]
+policy = "per_worker"
+```
+
+When running with `per_worker` policy, Function won't auto-reload on edits. You will need to manually restart it by running `supabase functions serve`.
diff --git a/apps/docs/content/guides/getting-started/ai-prompts.mdx b/apps/docs/content/guides/getting-started/ai-prompts.mdx
new file mode 100644
index 00000000000..412364c2bfb
--- /dev/null
+++ b/apps/docs/content/guides/getting-started/ai-prompts.mdx
@@ -0,0 +1,16 @@
+---
+title: AI Prompts
+subtitle: Prompts for working with Supabase using AI-powered IDE tools
+---
+
+We've curated a selection of prompts to help you work with Supabase using your favorite AI-powered IDE tools, such as GitHub Copilot or Cursor.
+
+## How to use
+
+Copy the prompt to a file in your repo.
+
+Use the "include file" feature from your AI tool to include the prompt when chatting with your AI assistant. For example, with GitHub Copilot, use `#`, in Cursor, use `@Files`, and in Zed, use `/file`.
+
+## Prompts
+
+
diff --git a/apps/docs/content/guides/getting-started/features.mdx b/apps/docs/content/guides/getting-started/features.mdx
index 6a982ddec9a..fdc5bfda954 100644
--- a/apps/docs/content/guides/getting-started/features.mdx
+++ b/apps/docs/content/guides/getting-started/features.mdx
@@ -16,7 +16,7 @@ Every project is a full Postgres database. [Docs](/docs/guides/database).
Store vector embeddings right next to the rest of your data. [Docs](/docs/guides/ai).
-### Auto-generated Rest API via PostgREST
+### Auto-generated REST API via PostgREST
RESTful APIs are auto-generated from your database, without a single line of code. [Docs](/docs/guides/api#rest-api-overview).
@@ -66,13 +66,13 @@ Deploy read-only databases across multiple regions, for lower latency and better
Launch the Supabase stack on Fly.io edge network. [Docs](/docs/guides/platform/fly-postgres).
-### Log Drains
+### Log drains
Export Supabase logs at to 3rd party providers and external tooling. [Docs](/docs/guides/platform/log-drains).
## Studio
-### Studio Single Sign On
+### Studio Single Sign-On
Login to the Supabase dashboard via SSO. [Docs](/docs/guides/platform/sso).
@@ -118,7 +118,7 @@ Control the data each user can access with Postgres Policies. [Docs](/docs/guide
Add Captcha to your sign-in, sign-up, and password reset forms. [Docs](/docs/guides/auth/auth-captcha).
-### Server-side Auth
+### Server-Side Auth
Helpers for implementing user authentication in popular server-side languages and frameworks like Next.js, SvelteKit and Remix. [Docs](/docs/guides/auth/server-side).
@@ -183,11 +183,11 @@ Unofficial libraries are supported by the community.
Supabase Features are in 4 different states - Private Alpha, Public Alpha, Beta and Generally Available.
-### Private Alpha
+### Private alpha
Features are initially launched as a private alpha to gather feedback from the community. To join our early access program, send an email to product-ops@supabase.io.
-### Public Alpha
+### Public alpha
The alpha stage indicates that the API might change in the future, not that the service isn’t stable. Even though the [uptime Service Level Agreement](https://supabase.com/sla) does not cover products in Alpha, we do our best to have the service as stable as possible.
@@ -195,7 +195,7 @@ The alpha stage indicates that the API might change in the future, not that the
Features in Beta are tested by an external penetration tester for security issues. The API is guaranteed to be stable and there is a strict communication process for breaking changes.
-### Generally Available
+### Generally available
In addition to the Beta requirements, features in GA are covered by the [uptime SLA](https://supabase.com/sla).
diff --git a/apps/docs/content/guides/getting-started/quickstarts/redwoodjs.mdx b/apps/docs/content/guides/getting-started/quickstarts/redwoodjs.mdx
index be4ca73f67e..025a22e5ba2 100644
--- a/apps/docs/content/guides/getting-started/quickstarts/redwoodjs.mdx
+++ b/apps/docs/content/guides/getting-started/quickstarts/redwoodjs.mdx
@@ -116,7 +116,7 @@ hideToc: true
- ```prisma api/prisma/schema.prisma
+ ```prisma api/db/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
diff --git a/apps/docs/content/guides/getting-started/tutorials/with-kotlin.mdx b/apps/docs/content/guides/getting-started/tutorials/with-kotlin.mdx
index 513a651444d..4f9a0527b1e 100644
--- a/apps/docs/content/guides/getting-started/tutorials/with-kotlin.mdx
+++ b/apps/docs/content/guides/getting-started/tutorials/with-kotlin.mdx
@@ -96,6 +96,8 @@ plugins {
}
```
+{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
+
### Set up Hilt for dependency injection
In the `build.gradle` (app) file, add the following:
@@ -134,6 +136,8 @@ class MainActivity : ComponentActivity() {
}
```
+{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
+
### Provide Supabase instances with Hilt
To make the app easier to test, create a `SupabaseModule.kt` file as follows:
diff --git a/apps/docs/content/guides/getting-started/tutorials/with-nextjs.mdx b/apps/docs/content/guides/getting-started/tutorials/with-nextjs.mdx
index d43d01b8ab5..277a212022f 100644
--- a/apps/docs/content/guides/getting-started/tutorials/with-nextjs.mdx
+++ b/apps/docs/content/guides/getting-started/tutorials/with-nextjs.mdx
@@ -301,7 +301,7 @@ meta="utils/supabase/middleware.ts"
## Set up a login page
-### Login and Signup form
+### Login and signup form
Create a login/signup page for your application:
diff --git a/apps/docs/content/guides/getting-started/tutorials/with-refine.mdx b/apps/docs/content/guides/getting-started/tutorials/with-refine.mdx
index 0192a305f14..f3a901e69a6 100644
--- a/apps/docs/content/guides/getting-started/tutorials/with-refine.mdx
+++ b/apps/docs/content/guides/getting-started/tutorials/with-refine.mdx
@@ -97,7 +97,7 @@ You can find the full contents of this file [here](https://raw.githubusercontent
In order for us to add login and user profile pages in this App, we have to tweak the `` component inside `App.tsx`.
-### The `` Component
+### The `` component
The `App.tsx` file initially looks like this:
diff --git a/apps/docs/content/guides/getting-started/tutorials/with-swift.mdx b/apps/docs/content/guides/getting-started/tutorials/with-swift.mdx
index 33e597d1210..fe6999a3f94 100644
--- a/apps/docs/content/guides/getting-started/tutorials/with-swift.mdx
+++ b/apps/docs/content/guides/getting-started/tutorials/with-swift.mdx
@@ -293,6 +293,8 @@ Update the entry point to the newly created `AppView`. Run in Xcode to launch yo
Every Supabase project is configured with [Storage](/docs/guides/storage) for managing large files like
photos and videos.
+{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
+
### Add PhotosPicker
Let's add support for the user to pick an image from the library and upload it.
@@ -332,6 +334,8 @@ enum TransferError: Error {
}
```
+{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
+
#### Add PhotosPicker to profile page
```swift ProfileView.swift
diff --git a/apps/docs/content/guides/integrations/vercel-marketplace.mdx b/apps/docs/content/guides/integrations/vercel-marketplace.mdx
index be0ef42121c..ec92cffa11c 100644
--- a/apps/docs/content/guides/integrations/vercel-marketplace.mdx
+++ b/apps/docs/content/guides/integrations/vercel-marketplace.mdx
@@ -10,7 +10,7 @@ The Vercel Marketplace is a feature that allows you to manage third-party resour
When you create an organization and projects through Vercel Marketplace, they function just like those created directly within Supabase. However, the billing is handled through your Vercel account, and you can manage your resources directly from the Vercel dashboard or CLI. Additionally, environment variables are automatically synchronized, making them immediately available for your connected projects.
-For more information, see [Introducing the Vercel Marketplace](https://vercel.com/blog/share/introducing-the-vercel-marketplace) blog post.
+For more information, see [Introducing the Vercel Marketplace](https://vercel.com/blog/introducing-the-vercel-marketplace) blog post.
diff --git a/apps/docs/content/guides/local-development/cli/getting-started.mdx b/apps/docs/content/guides/local-development/cli/getting-started.mdx
index 6319a53ddf5..fa4e927ca85 100644
--- a/apps/docs/content/guides/local-development/cli/getting-started.mdx
+++ b/apps/docs/content/guides/local-development/cli/getting-started.mdx
@@ -131,7 +131,7 @@ If you have any Supabase containers running locally, stop them and delete their
Remember to save any local schema and data changes before stopping because the `--no-backup` flag will delete them.
```sh
-supabase db diff my_schema
+supabase db diff -f my_schema
supabase db dump --local --data-only > supabase/seed.sql
supabase stop --no-backup
```
diff --git a/apps/docs/content/guides/local-development/overview.mdx b/apps/docs/content/guides/local-development/overview.mdx
index 5b1d5912158..6e1c8a5cc60 100644
--- a/apps/docs/content/guides/local-development/overview.mdx
+++ b/apps/docs/content/guides/local-development/overview.mdx
@@ -335,6 +335,29 @@ This will upload files from `supabase/images` directory to a bucket named `image
supabase seed buckets
```
+### Sync any schema with `--schema`
+
+You can synchronize your database with a specific schema using the `--schema` option as follows:
+
+```bash
+supabase db pull --schema
+```
+
+
+
+Using `--schema`
+
+If the local `supabase/migrations` directory is empty, the db pull command will ignore the `--schema` parameter.
+
+To fix this, you can pull twice:
+
+```bash
+supabase db pull
+supabase db pull --schema
+```
+
+
+
## Limitations and considerations
The local development environment is not as feature-complete as the Supabase Platform. Here are some of the differences:
diff --git a/apps/docs/content/guides/platform/backups.mdx b/apps/docs/content/guides/platform/backups.mdx
index 5f77fef5a5b..c6c413027b6 100644
--- a/apps/docs/content/guides/platform/backups.mdx
+++ b/apps/docs/content/guides/platform/backups.mdx
@@ -135,6 +135,41 @@ A date and time picker will be provided upon pressing the `Start a restore` butt
After locking in the desired point in time to recover to, The Dashboard will then prompt for a review and confirmation before proceeding with the restoration. The project will be inaccessible following this. As such, do ensure to allot for downtime beforehand. This is dependent on the size of the database. The larger it is, the longer the downtime will be. Once the confirmation has been given, the latest physical backup available is downloaded to the project and the database is partially restored. WAL files generated after this physical backup up to the specified point-in-time are then downloaded. The underlying records of transactions in these files are replayed against the database to complete the restoration. The Dashboard will display a notification once the restoration completes.
+## Restore to a new project
+
+Supabase provides a convenient way to restore data from an existing project into a completely new one. Whether you're using physical backups or Point-in-Time recovery (PITR), this feature allows you to duplicate project data with ease, perform testing safely, or recover data for analysis. Access to this feature is exclusive to users on paid plans and requires that physical backups are enabled for the source project.
+
+
+
+PITR is an additional add-on available for organizations on a paid plan with physical backups enabled.
+
+
+
+To begin, switch to the source project—the project containing the data you wish to restore—and go to the [database backups](https://supabase.com/dashboard/project/_/database/backups/restore-to-new-project) page. Select the **Restore to a New Project** tab.
+
+A list of available backups is displayed. Select the backup you want to use and click the "Restore" button. For projects with PITR enabled, use the date and time selector to specify the exact point in time from which you wish to restore data.
+
+Once you’ve made your choice, Supabase takes care of the rest. A new project is automatically created, replicating key configurations from the original, including the compute instance size, disk attributes, SSL enforcement settings, and network restrictions. The data will remain in the same region as the source project to ensure compliance with data residency requirements. The entire process is fully automated.
+
+
+
+The time required to complete the restoration can vary depending largely on the volume of data involved. If you have a large amount of data you can opt for higher performing disk attributes on the source project _before_ starting a clone operation. These disk attributes will be replicated to the new project. This incurs additional costs which will be displayed before starting.
+
+
+
+There are a few important restrictions to be aware of with the "Restore to a New Project" process:
+
+- Projects that are created through the restoration process cannot themselves be used as a source for further clones at this time.
+- The feature is only accessible to paid plan users with physical backups enabled, ensuring that the necessary resources and infrastructure are available for the restore process.
+
+Before starting the restoration, you’ll be presented with an overview of the costs associated with creating the new project. The new project will incur additional monthly expenses based on the mirrored resources from the source project. It’s important to review these costs carefully before proceeding.
+
+Once the restoration is complete, the new project will be available in your dashboard and will include all data, tables, schemas, and selected settings from the chosen backup source. It is recommended to thoroughly review the new project and perform any necessary tests to ensure everything has been restored as expected.
+
+New projects are completely independent of their source, and as such can be modified and used as desired.
+
+Restoring to a new project is an excellent way to manage environments more effectively. You can use this feature to create staging environments for testing, experiment with changes without risk to production data, or swiftly recover from unexpected data loss scenarios.
+
## Troubleshooting
### Logical backups
diff --git a/apps/docs/content/guides/platform/compute-and-disk.mdx b/apps/docs/content/guides/platform/compute-and-disk.mdx
index 6965dba9b76..74aeec43fef 100644
--- a/apps/docs/content/guides/platform/compute-and-disk.mdx
+++ b/apps/docs/content/guides/platform/compute-and-disk.mdx
@@ -10,11 +10,9 @@ Every project on the Supabase Platform comes with its own dedicated Postgres ins
The following table describes the base instances, Nano (free plan) and Micro (paid plans), with additional compute instance sizes available if you need extra performance when scaling up.
-
+
-If you upgraded your Supabase organization from the Free plan to a paid plan, any projects created on the Free plan will remain on Nano instances due to the upgrade process [incurring downtime](/docs/guides/platform/compute-and-disk#upgrade-downtime).
-
-Since every project on a paid plan is already paying for a Micro instance you can upgrade to Micro at no additional charge. See [Supabase Pricing](https://supabase.com/pricing) for more information.
+In Pro organizations, Nano Compute are billed at the same price as Micro Compute. It is recommended to upgrade your Project from Nano Compute to Micro Compute when it's convenient for you. Compute sizes are not auto-upgraded because of the downtime incurred. See [Supabase Pricing](https://supabase.com/pricing) for more information.
@@ -110,13 +108,14 @@ Be aware that increasing IOPS or throughput incurs additional charges.
When selecting your disk, it's essential to focus on the performance needs of your workload. Here's a comparison of our available disk types:
-| | General Purpose SSD (gp3) | High Performance SSD (io2) |
-| ----------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
-| **Use Case** | General workloads, development environments, small to medium databases | High-performance needs, large-scale databases, mission-critical applications |
-| **Max Disk Size** | 16 TB | 60 TB |
-| **Max IOPS** | 16,000 IOPS (at 32 GB disk size) | 80,000 IOPS (at 80 GB disk size) |
-| **Throughput** | 125 MiB/s (default) to 1,000 MiB/s (maximum) | Automatically scales with IOPS |
-| **Best For** | Great value for most use cases | Low latency and very high IOPS requirements |
+| | General Purpose SSD (gp3) | High Performance SSD (io2) |
+| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
+| **Use Case** | General workloads, development environments, small to medium databases | High-performance needs, large-scale databases, mission-critical applications |
+| **Max Disk Size** | 16 TB | 60 TB |
+| **Max IOPS** | 16,000 IOPS (at 32 GB disk size) | 80,000 IOPS (at 80 GB disk size) |
+| **Throughput** | 125 MiB/s (default) to 1,000 MiB/s (maximum) | Automatically scales with IOPS |
+| **Best For** | Great value for most use cases | Low latency and very high IOPS requirements |
+| **Pricing** | Disk: 8 GB included, then $0.125 per GB IOPS: 3,000 included, then $0.024 per IOPS Throughput: 125 Mbps included, then $0.95 per Mbps | Disk: $0.195 per GB IOPS: $0.119 per IOPS Throughput: Scales with IOPS at no additional cost |
For general, day-to-day operations, gp3 should be more than enough. If you need high throughput and IOPS for critical systems, io2 will provide the performance required.
diff --git a/apps/docs/content/guides/platform/database-size.mdx b/apps/docs/content/guides/platform/database-size.mdx
index bb9174b5f9f..a4774aa07a0 100644
--- a/apps/docs/content/guides/platform/database-size.mdx
+++ b/apps/docs/content/guides/platform/database-size.mdx
@@ -139,8 +139,22 @@ Once you have reclaimed space, you can run the following to disable [read-only](
set default_transaction_read_only = 'off';
```
+### Disk Size Distribution
+
+You can check the distribution of your disk size on your [project's compute and disk page](/dashboard/_/settings/compute-and-disk).
+
+
+
+Your disk size usage falls in three categories:
+
+- **Database** - Disk usage by the database. This includes the actual data, indexes, materialized views, ...
+- **WAL** - Disk usage by the write-ahead log. The usage depends on your WAL settings and the amount of data being written to the database.
+- **System** - Disk usage reserved by the system to ensure the database can operate smoothly. Users cannot modify this and it should only take very little space.
+
### Reducing disk size
Disks don't automatically downsize during normal operation. Once you have [reduced your database size](/docs/guides/platform/database-size#database-size), they _will_ automatically "right-size" during a [project upgrade](/docs/guides/platform/upgrading). The final disk size after the upgrade is 1.2x the size of the database with a minimum of 8 GB. For example, if your database size is 100GB, and you have a 200GB disk, the size after a project upgrade will be 120 GB.
+In case you have a large WAL directory, you may [modify WAL settings](/docs/guides/database/custom-postgres-config) such as `max_wal_size`. Use at your own risk as changing these settings can have side effects. To query your current WAL size, use `SELECT SUM(size) FROM pg_ls_waldir()`.
+
In the event that your project is already on the latest version of Postgres and cannot be upgraded, a new version of Postgres will be released approximately every week which you can then upgrade to once it becomes available.
diff --git a/apps/docs/content/guides/queues.mdx b/apps/docs/content/guides/queues.mdx
new file mode 100644
index 00000000000..8130a357edc
--- /dev/null
+++ b/apps/docs/content/guides/queues.mdx
@@ -0,0 +1,34 @@
+---
+title: Supabase Queues
+subtitle: 'Durable Message Queues with Guaranteed Delivery in Postgres'
+---
+
+Supabase Queues is a Postgres-native durable Message Queue system with guaranteed delivery built on the [pgmq database extension](https://github.com/tembo-io/pgmq). It offers developers a seamless way to persist and process Messages in the background while improving the resiliency and scalability of their applications and services.
+
+Queues couples the reliability of Postgres with the simplicity Supabase's platform and developer experience, enabling developers to manage Background Tasks with zero configuration.
+
+## Features
+
+- **Postgres Native**
+
+ Built on top of the `pgmq` database extension, create and manage Queues with any Postgres tooling.
+- **Guaranteed Message Delivery**
+
+ Messages added to Queues are guaranteed to be delivered to your consumers.
+- **Exactly Once Message Delivery**
+ A Message is delivered exactly once to a consumer within a customizable visibility window.
+- **Message Durability and Archival**
+
+ Messages are stored in Postgres and you can choose to archive them for analytical or auditing purposes.
+- **Granular Authorization**
+
+ Control client-side consumer access to Queues with API permissions and Row Level Security (RLS) policies.
+- **Queue Management and Monitoring**
+
+ Create, manage, and monitor Queues and Messages in the Supabase Dashboard.
+
+## Resources
+
+- [Quickstart](/docs/guides/queues/quickstart)
+- [API Reference](/docs/guides/queues/api)
+- [`pgmq` GitHub Repository](https://github.com/tembo-io/pgmq)
diff --git a/apps/docs/content/guides/queues/api.mdx b/apps/docs/content/guides/queues/api.mdx
new file mode 100644
index 00000000000..01b1aed2688
--- /dev/null
+++ b/apps/docs/content/guides/queues/api.mdx
@@ -0,0 +1,62 @@
+---
+title: API
+---
+
+{/* */}
+When you create a Queue in Supabase, you can choose to create helper database functions in the `pgmq_public` schema. This schema exposes operations to manage Queue Messages to consumers client-side, but does not expose functions for creating or dropping Queues.
+
+Database functions in `pgmq_public` can be exposed via Supabase Data API so consumers client-side can call them. Visit the [Quickstart](/docs/guides/queues/quickstart) for an example.
+
+## `pgmq_public.pop(queue_name)`
+
+Retrieves the next available message and deletes it from the specified Queue.
+
+- `queue_name` (text): Queue name
+
+---
+
+### `pgmq_public.send(queue_name, message, sleep_seconds)`
+
+Adds a Message to the specified Queue, optionally delaying its visibility to all consumers by a number of seconds.
+
+- `queue_name` (text): Queue name
+- `message` (jsonb): Message payload to send
+- `sleep_seconds` (integer, optional): Delay message visibility by specified seconds. Defaults to 0
+
+---
+
+### `pgmq_public.send_batch(queue_name, messages, sleep_seconds)`
+
+Adds a batch of Messages to the specified Queue, optionally delaying their availability to all consumers by a number of seconds.
+
+- `queue_name` (text): Queue name
+- `messages` (jsonb[]): Array of message payloads to send
+- `sleep_seconds` (integer, optional): Delay messages visibility by specified seconds. Defaults to 0
+
+---
+
+### `pgmq_public.archive(queue_name, message_id)`
+
+Archives a Message by moving it from the Queue table to the Queue's archive table.
+
+- `queue_name` (text): Queue name
+- `message_id` (bigint): ID of the Message to archive
+
+---
+
+### `pgmq_public.delete(queue_name, message_id)`
+
+Permanently deletes a Message from the specified Queue.
+
+- `queue_name` (text): Queue name
+- `message_id` (bigint): ID of the Message to delete
+
+---
+
+### `pgmq_public.read(queue_name, sleep_seconds, n)`
+
+Reads up to "n" Messages from the specified Queue with an optional "sleep_seconds" (visibility timeout).
+
+- `queue_name` (text): Queue name
+- `sleep_seconds` (integer): Visibility timeout in seconds
+- `n` (integer): Maximum number of Messages to read
diff --git a/apps/docs/content/guides/queues/quickstart.mdx b/apps/docs/content/guides/queues/quickstart.mdx
new file mode 100644
index 00000000000..426f057ea6c
--- /dev/null
+++ b/apps/docs/content/guides/queues/quickstart.mdx
@@ -0,0 +1,195 @@
+---
+title: Quickstart
+subtitle: 'Learn how to use Supabase Queues to add and read messages'
+---
+
+{/* */}
+This guide is an introduction to interacting with Supabase Queues via the Dashboard and official client library. Check out [Queues API Reference](/docs/guides/queues/api) for more details on our API.
+
+## Concepts
+
+Supabase Queues is a pull-based Message Queue consisting of three main components: Queues, Messages, and Queue Types.
+
+### Pull-Based Queue
+
+A pull-based Queue is a Message storage and delivery system where consumers actively fetch Messages when they're ready to process them - similar to constantly refreshing a webpage to display the latest updates. Our pull-based Queues process Messages in a First-In-First-Out (FIFO) manner without priority levels.
+
+### Message
+
+A Message in a Queue is a json object that is stored until a consumer explicitly processes and removes it, like a task waiting in a to-do list until someone checks and completes it.
+
+### Queue Types
+
+Supabase Queues offers three types of Queues:
+
+- **Basic Queue**: A durable Queue that stores Messages in a logged table.
+- **Unlogged Queue**: A transient Queue that stores Messages in an unlogged table for better performance but may result in loss of Queue Messages.
+
+- **Partitioned Queue** (_Coming Soon_): A durable and scalable Queue that stores Messages in multiple table partitions for better performance.
+
+## Create Queues
+
+To get started, navigate to the [Supabase Queues](/dashboard/project/_/integrations/queues/overview) Postgres Module under Integrations in the Dashboard and enable the `pgmq` extension.
+
+
+
+`pgmq` extension is available in Postgres version 15.6.1.143 or later.
+
+
+
+
+
+On the [Queues page](/dashboard/project/_/integrations/queues/queues):
+
+- Click **Add a new queue** button
+
+
+
+If you've already created a Queue click the **Create a queue** button instead.
+
+
+
+- Name your queue
+
+
+
+Queue names can only be lowercase and hyphens and underscores are permitted.
+
+
+
+- Select your [Queue Type](#queue-types)
+
+
+
+### What happens when you create a queue?
+
+Every new Queue creates two tables in the `pgmq` schema. These tables are `pgmq.q_` to store and process active messages and `pgmq.a_` to store any archived messages.
+
+A "Basic Queue" will create `pgmq.q_` and `pgmq.a_` tables as logged tables.
+
+However, an "Unlogged Queue" will create `pgmq.q_` as an unlogged table for better performance while sacrificing durability. The `pgmq.a_` table will still be created as a logged table so your archived messages remain safe and secure.
+
+## Expose Queues to client-side consumers
+
+Queues, by default, are not exposed over Supabase Data API and are only accessible via Postgres clients.
+
+However, you may grant client-side consumers access to your Queues by enabling the Supabase Data API and granting permissions to the Queues API, which is a collection of database functions in the `pgmq_public` schema that wraps the database functions in the `pgmq` schema.
+
+This is to prevent direct access to the `pgmq` schema and its tables (RLS is not enabled by default on any tables) and database functions.
+
+To get started, navigate to the Queues [Settings page](/dashboard/project/_/integrations/queues/settings) and toggle on “Expose Queues via PostgREST”. Once enabled, Supabase creates and exposes a `pgmq_public` schema containing database function wrappers to a subset of `pgmq`'s database functions.
+
+
+
+### Enable RLS on your tables in `pgmq` schema
+
+For security purposes, you must enable Row Level Security (RLS) on all Queue tables (all tables in `pgmq` schema that begin with `q_`) if the Data API is enabled.
+
+You’ll want to create RLS policies for any Queues you want your client-side consumers to interact with.
+
+
+
+### Grant permissions to `pgmq_public` database functions
+
+On top of enabling RLS and writing RLS policies on the underlying Queue tables, you must grant the correct permissions to the `pgmq_public` database functions for each Data API role.
+
+The permissions required for each Queue API database function:
+
+| **Operations** | **Permissions Required** |
+| ------------------- | ------------------------ |
+| `send` `send_batch` | `Select` `Insert` |
+| `read` `pop` | `Select` `Update` |
+| `archive` `delete` | `Select` `Delete` |
+
+
+
+
+
+`postgres` and `service_role` roles should never be exposed client-side.
+
+
+
+### Enqueuing and Dequeuing Messages
+
+Once your Queue has been created, you can begin enqueuing and dequeuing Messages.
+
+Here's a TypeScript example using the official Supabase client library:
+
+```tsx
+import { createClient } from '@supabase/supabase-js'
+
+const supabaseUrl = 'supabaseURL'
+const supabaseKey = 'supabaseKey'
+
+const supabase = createClient(supabaseUrl, supabaseKey)
+
+const QueuesTest: React.FC = () => {
+ //Add a Message
+ const sendToQueue = async () => {
+ const result = await supabase.rpc('send', {
+ queue_name: 'foo',
+ message: { hello: 'world' },
+ sleep_seconds: 30,
+ })
+ console.log(result)
+ }
+
+ //Dequeue Message
+ const popFromQueue = async () => {
+ const result = await supabase.rpc('pop', { queue_name: 'foo' })
+ console.log(result)
+ }
+
+ return (
+
+
Queue Test Component
+
+
+
+ )
+}
+
+export default QueuesTest
+```
diff --git a/apps/docs/content/guides/self-hosting.mdx b/apps/docs/content/guides/self-hosting.mdx
index 4c1da2e5519..1871402e392 100644
--- a/apps/docs/content/guides/self-hosting.mdx
+++ b/apps/docs/content/guides/self-hosting.mdx
@@ -84,6 +84,11 @@ The following third-party providers have shown consistent support for the self-h
description: 'Deploys using Kubernetes.',
href: 'https://stackgres.io/blog/running-supabase-on-top-of-stackgres/',
},
+ {
+ name: 'Pigsty',
+ description: 'Deploys using Ansible.',
+ href: 'https://pigsty.io/blog/db/supabase/',
+ },
].map((x) => (
diff --git a/apps/docs/content/guides/storage/security/access-control.mdx b/apps/docs/content/guides/storage/security/access-control.mdx
index 8240030d744..fe402991f0d 100644
--- a/apps/docs/content/guides/storage/security/access-control.mdx
+++ b/apps/docs/content/guides/storage/security/access-control.mdx
@@ -80,7 +80,7 @@ Allow a user to access a file that was previously uploaded by the same user:
create policy "Individual user Access"
on storage.objects for select
to authenticated
-using ( (select auth.uid()) = owner_id );
+using ( (select auth.uid()) = owner_id::uuid );
```
---
diff --git a/apps/docs/content/troubleshooting/why-is-my-camelcase-name-not-working-in-postgres-functions-or-rls-policies-EJMzVd.mdx b/apps/docs/content/troubleshooting/why-is-my-camelcase-name-not-working-in-postgres-functions-or-rls-policies-EJMzVd.mdx
new file mode 100644
index 00000000000..889a5c2fc09
--- /dev/null
+++ b/apps/docs/content/troubleshooting/why-is-my-camelcase-name-not-working-in-postgres-functions-or-rls-policies-EJMzVd.mdx
@@ -0,0 +1,11 @@
+---
+title = "Why is my camelCase name not working in Postgres functions or RLS policies?"
+github_url = "https://github.com/orgs/supabase/discussions/12893"
+date_created = "2023-03-08T16:26:51+00:00"
+topics = [ "database" ]
+database_id = "9dbcf760-7b1f-4cc4-8653-4e884fd02dad"
+---
+
+Avoid camelCase (upper case letters) if possible when naming functions, tables, columns, and variables. You must enclose "camelCase" in double quotes when you define it or use it. YOU WILL FORGET. Use snake_case instead and make your life easier.
+
+Note to Prisma users, you will likely have to deal with it.
diff --git a/apps/docs/docs/ref/javascript/introduction.mdx b/apps/docs/docs/ref/javascript/introduction.mdx
index ac1adb04ab3..38419887755 100644
--- a/apps/docs/docs/ref/javascript/introduction.mdx
+++ b/apps/docs/docs/ref/javascript/introduction.mdx
@@ -5,3 +5,5 @@ hideTitle: true
---
This reference documents every object and method available in Supabase's isomorphic JavaScript library, `supabase-js`. You can use `supabase-js` to interact with your Postgres database, listen to database changes, invoke Deno Edge Functions, build login and user management functionality, and manage large files.
+
+To convert SQL queries to `supabase-js` calls, use the [SQL to REST API translator](/docs/guides/api/sql-to-rest).
diff --git a/apps/docs/docs/ref/kotlin/installing.mdx b/apps/docs/docs/ref/kotlin/installing.mdx
index c3eb71b2374..93a918c49ff 100644
--- a/apps/docs/docs/ref/kotlin/installing.mdx
+++ b/apps/docs/docs/ref/kotlin/installing.mdx
@@ -30,6 +30,8 @@ custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supab
Checkout the different READMEs for information about supported Kotlin targets.
+ *Note that the minimum Android SDK version is 26. For lower versions, you need to enable [core library desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring).*
+
- {/* */}
+
{children}
diff --git a/apps/docs/features/directives/CodeSample.client.tsx b/apps/docs/features/directives/CodeSample.client.tsx
index 8cde6cf1ae9..597a482788a 100644
--- a/apps/docs/features/directives/CodeSample.client.tsx
+++ b/apps/docs/features/directives/CodeSample.client.tsx
@@ -4,6 +4,17 @@ import Link from 'next/link'
import { useState, type PropsWithChildren } from 'react'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from 'ui'
+import { Admonition } from 'ui-patterns/admonition'
+
+export function CodeSampleDummy() {
+ return (
+
+ The $CodeSample directive with external repos is not supported in local
+ development because it relies on a GitHub API key. Please check the preview site to see the
+ final UI.
+
+ )
+}
export function CodeSampleWrapper({
children,
diff --git a/apps/docs/features/directives/CodeSample.test.ts b/apps/docs/features/directives/CodeSample.test.ts
index 65dd9bdb26d..a3ae68b0e1e 100644
--- a/apps/docs/features/directives/CodeSample.test.ts
+++ b/apps/docs/features/directives/CodeSample.test.ts
@@ -14,10 +14,17 @@ const transformWithMock = codeSampleRemark({
let env: NodeJS.Process['env']
+vi.mock('~/lib/constants', () => ({
+ IS_PLATFORM: true,
+}))
+
describe('$CodeSample', () => {
beforeAll(() => {
env = process.env
- process.env = { NODE_ENV: 'test', NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA: '1234567890' }
+ process.env = {
+ NODE_ENV: 'test',
+ NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA: '1234567890',
+ }
})
afterAll(() => {
diff --git a/apps/docs/features/directives/CodeSample.ts b/apps/docs/features/directives/CodeSample.ts
index d97f0c3fe79..ac81693a120 100644
--- a/apps/docs/features/directives/CodeSample.ts
+++ b/apps/docs/features/directives/CodeSample.ts
@@ -46,8 +46,11 @@ import { visitParents } from 'unist-util-visit-parents'
import { z, type SafeParseError } from 'zod'
import { fetchWithNextOptions } from '~/features/helpers.fetch'
+import { IS_PLATFORM } from '~/lib/constants'
import { EXAMPLES_DIRECTORY } from '~/lib/docs'
+const ALLOW_LISTED_GITHUB_ORGS = ['supabase', 'supabase-community'] as [string, ...string[]]
+
const linesSchema = z.array(z.tuple([z.coerce.number(), z.coerce.number()]))
const linesValidator = z
.string()
@@ -73,7 +76,9 @@ type AdditionalMeta = {
const codeSampleExternalSchema = z.object({
external: z.coerce.boolean().refine((v) => v === true),
- org: z.string(),
+ org: z.enum(ALLOW_LISTED_GITHUB_ORGS, {
+ errorMap: () => ({ message: 'Org must be one of: ' + ALLOW_LISTED_GITHUB_ORGS.join(', ') }),
+ }),
repo: z.string(),
commit: z.string(),
path: z.string().transform((v) => (v.startsWith('/') ? v : `/${v}`)),
@@ -137,6 +142,12 @@ async function fetchSourceCodeContent(tree: Root, deps: Dependencies) {
const isExternal = getAttributeValueExpression(getAttributeValue(node, 'external')) === 'true'
if (isExternal) {
+ if (!IS_PLATFORM) {
+ node.name = 'CodeSampleDummy'
+ node.attributes = []
+ return
+ }
+
const org = getAttributeValue(node, 'org')
const repo = getAttributeValue(node, 'repo')
const commit = getAttributeValue(node, 'commit')
diff --git a/apps/docs/features/directives/utils.ts b/apps/docs/features/directives/utils.ts
index eb67d138d91..d52e1fd94cd 100644
--- a/apps/docs/features/directives/utils.ts
+++ b/apps/docs/features/directives/utils.ts
@@ -9,6 +9,7 @@ import { mdxjs } from 'micromark-extension-mdxjs'
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
import { getGitHubFileContents } from '~/lib/octokit'
+import { getGitHubFileContentsImmutableOnly } from '~/lib/octokit'
import { codeSampleRemark } from './CodeSample'
type Transformer = (ast: Root) => Root | Promise
@@ -31,6 +32,8 @@ export function preprocessMdxWithDefaults(mdx: string) {
return preprocessMdx(mdx, [
remarkMkDocsAdmonition(),
remarkPyMdownTabs(),
- codeSampleRemark({ fetchFromGitHub: getGitHubFileContents }),
+ codeSampleRemark({
+ fetchFromGitHub: getGitHubFileContentsImmutableOnly,
+ }),
])
}
diff --git a/apps/docs/features/docs/GuidesMdx.utils.tsx b/apps/docs/features/docs/GuidesMdx.utils.tsx
index d21e7fe6e9e..1c8b28a4282 100644
--- a/apps/docs/features/docs/GuidesMdx.utils.tsx
+++ b/apps/docs/features/docs/GuidesMdx.utils.tsx
@@ -1,7 +1,6 @@
import matter from 'gray-matter'
import { fromMarkdown } from 'mdast-util-from-markdown'
-import { gfmFromMarkdown, gfmToMarkdown } from 'mdast-util-gfm'
-import { toMarkdown } from 'mdast-util-to-markdown'
+import { gfmFromMarkdown } from 'mdast-util-gfm'
import { gfm } from 'micromark-extension-gfm'
import { type Metadata, type ResolvingMetadata } from 'next'
import { notFound } from 'next/navigation'
@@ -26,6 +25,7 @@ const PUBLISHED_SECTIONS = [
'ai',
'api',
'auth',
+ 'cron',
'database',
'deployment',
'functions',
@@ -35,6 +35,7 @@ const PUBLISHED_SECTIONS = [
'local-development',
'monitoring-troubleshooting',
'platform',
+ 'queues',
'realtime',
'resources',
'self-hosting',
diff --git a/apps/docs/features/docs/MdxBase.shared.tsx b/apps/docs/features/docs/MdxBase.shared.tsx
index d90dfdca25e..f10680b392c 100644
--- a/apps/docs/features/docs/MdxBase.shared.tsx
+++ b/apps/docs/features/docs/MdxBase.shared.tsx
@@ -35,7 +35,7 @@ import { RealtimeLimitsEstimator } from '~/components/RealtimeLimitsEstimator'
import { RegionsList } from '~/components/RegionsList'
import { SharedData } from '~/components/SharedData'
import StepHikeCompact from '~/components/StepHikeCompact'
-import { CodeSampleWrapper } from '~/features/directives/CodeSample.client'
+import { CodeSampleDummy, CodeSampleWrapper } from '~/features/directives/CodeSample.client'
import { Accordion, AccordionItem } from '~/features/ui/Accordion'
import * as CH from '~/features/ui/CodeHike'
import { ShowUntil } from '~/features/ui/ShowUntil'
@@ -53,6 +53,7 @@ const components = {
Button,
ButtonCard,
CH,
+ CodeSampleDummy,
CodeSampleWrapper,
CostWarning,
CreateClientSnippet,
diff --git a/apps/docs/features/docs/MdxBase.tsx b/apps/docs/features/docs/MdxBase.tsx
index 1bda6f1f0b1..20413a1cc7d 100644
--- a/apps/docs/features/docs/MdxBase.tsx
+++ b/apps/docs/features/docs/MdxBase.tsx
@@ -7,9 +7,14 @@ import remarkGfm from 'remark-gfm'
import rehypeKatex from 'rehype-katex'
import remarkMath from 'remark-math'
+import { AiPromptsIndex } from '~/app/guides/(with-sidebar)/getting-started/ai-prompts/[slug]/AiPromptsIndex'
import { preprocessMdxWithDefaults } from '~/features/directives/utils'
import { components } from '~/features/docs/MdxBase.shared'
+const serverOnlyComponents = {
+ AiPromptsIndex,
+}
+
const codeHikeOptions: CodeHikeConfig = {
theme: codeHikeTheme,
lineNumbers: true,
@@ -66,7 +71,7 @@ const MDXRemoteBase = async ({
return (
diff --git a/apps/docs/features/docs/Troubleshooting.ui.tsx b/apps/docs/features/docs/Troubleshooting.ui.tsx
index b3fec96bff8..80693679204 100644
--- a/apps/docs/features/docs/Troubleshooting.ui.tsx
+++ b/apps/docs/features/docs/Troubleshooting.ui.tsx
@@ -34,9 +34,9 @@ export async function TroubleshootingPreview({ entry }: { entry: ITroubleshootin
{...attributes}
>
- We're providing an additional alternative UX to creating database functions through the
- dashboard with the integration of our AI Assistant that you might have seen in the Auth
- Policies section.
-
-
-
- This preview also shares an improved Assistant interface where you may provide the Assistant
- with contexts in hopes to generate more relevant and higher quality outputs. Contexts that
- you may provide include specific schemas, and / or specific tables from your database.
-
-
- We'd hope to use this as a consistent pattern throughout the dashboard eventually if this
- feature preview proves itself to benefit most of our users, so as usual please do feel free
- to let us know what you think if the attached GitHub discussion above!
-
- {hasSpamWarning
- ? ` Rectify the following issues to improve your email's deliverability in order of priority:`
- : ` Address the following issues to improve your email's deliverability:`}
-
-
-
-
- Warning
- Description
+
+
+ {hasSpamWarning
+ ? ` Rectify the following issues to improve your email's deliverability in order of priority:`
+ : ` Address the following issues to improve your email's deliverability:`}
+
-
- )}
+ {
+ const sql = generatePolicyCreateSQL(policy)
+ setAiAssistantPanel({
+ open: true,
+ sqlSnippets: [sql],
+ initialInput: `Update the policy with name "${policy.name}" in the ${policy.schema} schema on the ${policy.table} table. It should...`,
+ suggestions: {
+ title: `I can help you make a change to the policy "${policy.name}" in the ${policy.schema} schema on the ${policy.table} table, here are a few example prompts to get you started:`,
+ prompts: [
+ 'Tell me how I can improve this policy...',
+ 'Duplicate this policy for another table...',
+ 'Add extra conditions to this policy...',
+ ],
+ },
+ })
+ }}
+ >
+
+