diff --git a/.github/workflows/docs-lint-v2.yml b/.github/workflows/docs-lint-v2.yml
index 3e3e27370a3..c27bd4f5641 100644
--- a/.github/workflows/docs-lint-v2.yml
+++ b/.github/workflows/docs-lint-v2.yml
@@ -45,6 +45,6 @@ jobs:
run: |
set -o pipefail
git diff --name-only origin/$BASE_REF HEAD \
- | { grep -E "^apps/docs/content/guides/(getting-started|ai|api|auth|database|deployment|functions)/" || test $? = 1; } \
+ | { grep -E "^apps/docs/content/guides/" || test $? = 1; } \
| xargs -r supa-mdx-lint --format rdf \
| reviewdog -f=rdjsonl -reporter=github-pr-review
diff --git a/apps/design-system/content/docs/tailwind-classes.mdx b/apps/design-system/content/docs/tailwind-classes.mdx
index 270d4886e58..a90261449b9 100644
--- a/apps/design-system/content/docs/tailwind-classes.mdx
+++ b/apps/design-system/content/docs/tailwind-classes.mdx
@@ -186,9 +186,3 @@ text-border-control
| `500` |
| `DEFAULT` |
| `600` |
-
-## Storybook
-
-The current colors are also auto documented in Storybook
-
-[Storybook Colors](https://ui-storybook-pre-release.vercel.app/)
diff --git a/apps/design-system/package.json b/apps/design-system/package.json
index 01cac2a43e7..c94bb23089c 100644
--- a/apps/design-system/package.json
+++ b/apps/design-system/package.json
@@ -34,7 +34,7 @@
"react-wrap-balancer": "^1.1.0",
"recharts": "^2.12.7",
"rehype-autolink-headings": "^7.1.0",
- "rehype-pretty-code": "^0.6.0",
+ "rehype-pretty-code": "^0.9.0",
"rehype-slug": "^6.0.0",
"remark": "^14.0.3",
"remark-code-import": "^1.2.0",
diff --git a/apps/docs/CONTRIBUTING.md b/apps/docs/CONTRIBUTING.md
index fa482554221..843af5ed2e4 100644
--- a/apps/docs/CONTRIBUTING.md
+++ b/apps/docs/CONTRIBUTING.md
@@ -77,7 +77,7 @@ You can usually identify a federated or reference doc because it uses a Next.js
Example spec file import:
```js
-import specFile from '~/spec/transforms/analytics_v0_openapi_deparsed.json' assert { type: 'json' }
+import specFile from '~/spec/transforms/analytics_v0_openapi_deparsed.json' with { type: 'json' }
```
Example repo definition:
diff --git a/apps/docs/app/guides/(with-sidebar)/config/page.tsx b/apps/docs/app/guides/(with-sidebar)/config/page.tsx
index 4707208e7e0..9ce99b1da78 100644
--- a/apps/docs/app/guides/(with-sidebar)/config/page.tsx
+++ b/apps/docs/app/guides/(with-sidebar)/config/page.tsx
@@ -5,7 +5,7 @@ import { type TOCHeader } from '~/components/GuidesTableOfContents'
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import type { Parameter } from '~/lib/refGenerator/refTypes'
-import specFile from '~/spec/cli_v1_config.yaml' assert { type: 'yml' }
+import specFile from '~/spec/cli_v1_config.yaml' with { type: 'yml' }
const meta = {
title: 'Supabase CLI config',
diff --git a/apps/docs/app/guides/(with-sidebar)/local-development/cli/config/page.tsx b/apps/docs/app/guides/(with-sidebar)/local-development/cli/config/page.tsx
index 4707208e7e0..9ce99b1da78 100644
--- a/apps/docs/app/guides/(with-sidebar)/local-development/cli/config/page.tsx
+++ b/apps/docs/app/guides/(with-sidebar)/local-development/cli/config/page.tsx
@@ -5,7 +5,7 @@ import { type TOCHeader } from '~/components/GuidesTableOfContents'
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import type { Parameter } from '~/lib/refGenerator/refTypes'
-import specFile from '~/spec/cli_v1_config.yaml' assert { type: 'yml' }
+import specFile from '~/spec/cli_v1_config.yaml' with { type: 'yml' }
const meta = {
title: 'Supabase CLI config',
diff --git a/apps/docs/app/guides/(with-sidebar)/self-hosting/analytics/config/page.tsx b/apps/docs/app/guides/(with-sidebar)/self-hosting/analytics/config/page.tsx
index 03a88cc171f..d7af68966fd 100644
--- a/apps/docs/app/guides/(with-sidebar)/self-hosting/analytics/config/page.tsx
+++ b/apps/docs/app/guides/(with-sidebar)/self-hosting/analytics/config/page.tsx
@@ -2,7 +2,7 @@ import Param from '~/components/Params'
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { MDXRemoteBase } from '~/features/docs/MdxBase'
-import specAnalyticsV0 from '~/spec/analytics_v0_config.yaml' assert { type: 'yml' }
+import specAnalyticsV0 from '~/spec/analytics_v0_config.yaml' with { type: 'yml' }
const meta = {
title: 'Analytics Self-hosting Config',
diff --git a/apps/docs/app/guides/(with-sidebar)/self-hosting/auth/config/page.tsx b/apps/docs/app/guides/(with-sidebar)/self-hosting/auth/config/page.tsx
index 9d6ff028b51..4a0d480754e 100644
--- a/apps/docs/app/guides/(with-sidebar)/self-hosting/auth/config/page.tsx
+++ b/apps/docs/app/guides/(with-sidebar)/self-hosting/auth/config/page.tsx
@@ -2,7 +2,7 @@ import Param from '~/components/Params'
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { MDXRemoteBase } from '~/features/docs/MdxBase'
-import specAuthV1 from '~/spec/gotrue_v1_config.yaml' assert { type: 'yml' }
+import specAuthV1 from '~/spec/gotrue_v1_config.yaml' with { type: 'yml' }
const meta = {
title: 'Auth Self-hosting Config',
diff --git a/apps/docs/app/guides/(with-sidebar)/self-hosting/realtime/config/page.tsx b/apps/docs/app/guides/(with-sidebar)/self-hosting/realtime/config/page.tsx
index d28ca1077a7..80d76288cd5 100644
--- a/apps/docs/app/guides/(with-sidebar)/self-hosting/realtime/config/page.tsx
+++ b/apps/docs/app/guides/(with-sidebar)/self-hosting/realtime/config/page.tsx
@@ -2,7 +2,7 @@ import Param from '~/components/Params'
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { MDXRemoteBase } from '~/features/docs/MdxBase'
-import specRealtimeV0 from '~/spec/realtime_v0_config.yaml' assert { type: 'yml' }
+import specRealtimeV0 from '~/spec/realtime_v0_config.yaml' with { type: 'yml' }
const meta = {
title: 'Realtime Self-hosting Config',
diff --git a/apps/docs/app/guides/(with-sidebar)/self-hosting/storage/config/page.tsx b/apps/docs/app/guides/(with-sidebar)/self-hosting/storage/config/page.tsx
index 1201543f943..a53adae5ec2 100644
--- a/apps/docs/app/guides/(with-sidebar)/self-hosting/storage/config/page.tsx
+++ b/apps/docs/app/guides/(with-sidebar)/self-hosting/storage/config/page.tsx
@@ -2,7 +2,7 @@ import Param from '~/components/Params'
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { MDXRemoteBase } from '~/features/docs/MdxBase'
-import specStorageV0 from '~/spec/storage_v0_config.yaml' assert { type: 'yml' }
+import specStorageV0 from '~/spec/storage_v0_config.yaml' with { type: 'yml' }
const meta = {
title: 'Storage Self-hosting Config',
diff --git a/apps/docs/components/MDX/auth_error_codes_table.mdx b/apps/docs/components/MDX/auth_error_codes_table.mdx
index 1447eadb689..7fc44588c95 100644
--- a/apps/docs/components/MDX/auth_error_codes_table.mdx
+++ b/apps/docs/components/MDX/auth_error_codes_table.mdx
@@ -10,6 +10,7 @@ To supplement HTTP status codes, Supabase Auth returns a string error code which
| `bad_oauth_state` | OAuth state (data echoed back by the OAuth provider to Supabase Auth) is not in the correct format. Indicates an issue with the OAuth provider integration. |
| `captcha_failed` | Captcha challenge could not be verified with the captcha provider. Check your captcha integration. |
| `conflict` | General database conflict, such as concurrent requests on resources that should not be modified concurrently. Can often occur when you have too many session refresh requests firing off at the same time for a user. Check your app for concurrency issues, and if detected, back off exponentially. |
+| `email_address_invalid` | Example and test domains are currently not supported. Please use a different email address. |
| `email_address_not_authorized` | Email sending is not allowed for this address as your project is using the default SMTP service. Emails can only be sent to members in your Supabase organization. If you want to send emails to others, please set up a [custom SMTP provider](/docs/guides/auth/auth-smtp). |
| `email_conflict_identity_not_deletable` | Unlinking this identity causes the user's account to change to an email address which is already used by another user account. Indicates an issue where the user has two different accounts using different primary email addresses. You may need to migrate user data to one of their accounts in this case. |
| `email_exists` | Email address already exists in the system. |
diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
index 481c0c944a6..9274f8c8ad2 100644
--- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
@@ -1004,6 +1004,10 @@ export const database: NavMenuConstant = {
name: 'pg_stat_monitor: Extended Query Performance Monitoring',
url: '/guides/database/extensions/pg_stat_monitor',
},
+ {
+ name: 'postgres_fdw: query data from an external Postgres server',
+ url: '/guides/database/extensions/postgres_fdw',
+ },
{
name: 'pgvector: Embeddings and vector similarity',
url: '/guides/database/extensions/pgvector',
@@ -1553,6 +1557,7 @@ export const realtime: NavMenuConstant = {
{ name: 'Quotas', url: '/guides/realtime/quotas' },
{ name: 'Architecture', url: '/guides/realtime/architecture' },
{ name: 'Message Protocol', url: '/guides/realtime/protocol', items: [] },
+ { name: 'Benchmarks', url: '/guides/realtime/benchmarks' },
],
},
{
@@ -2021,6 +2026,7 @@ export const platform: NavMenuConstant = {
{ name: 'Compute and Disk', url: '/guides/platform/compute-and-disk' },
{ name: 'Database Size', url: '/guides/platform/database-size' },
{ name: 'Fly Postgres', url: '/guides/platform/fly-postgres' },
+ { name: 'HIPAA Projects', url: '/guides/platform/hipaa-projects' },
{
name: 'Network Restrictions',
url: '/guides/platform/network-restrictions',
diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx
index 5f148720bb8..f18ba82147d 100644
--- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx
@@ -1,7 +1,7 @@
import Link from 'next/link'
import { BASE_PATH } from '~/lib/constants'
-import clientLibsCommon from '~/spec/common-cli.yml' assert { type: 'yml' }
+import clientLibsCommon from '~/spec/common-cli.yml' with { type: 'yml' }
import * as NavItems from './NavigationMenu.constants'
import { ChevronLeft } from 'lucide-react'
diff --git a/apps/docs/components/reference/CLICommandSection.tsx b/apps/docs/components/reference/CLICommandSection.tsx
index 012b9cdcb63..40b654d5576 100644
--- a/apps/docs/components/reference/CLICommandSection.tsx
+++ b/apps/docs/components/reference/CLICommandSection.tsx
@@ -5,7 +5,7 @@ import Options from '~/components/Options'
import Param from '~/components/Params'
import { TabPanel, Tabs } from '~/features/ui/Tabs'
import RefSubLayout from '~/layouts/ref/RefSubLayout'
-import spec from '~/spec/cli_v1_commands.yaml' assert { type: 'yml' }
+import spec from '~/spec/cli_v1_commands.yaml' with { type: 'yml' }
import RefDetailCollapse from './RefDetailCollapse'
export type Flag = {
diff --git a/apps/docs/components/reference/enrichments/cli/CliGlobalFlagsHandler.tsx b/apps/docs/components/reference/enrichments/cli/CliGlobalFlagsHandler.tsx
index 71f512f063d..79787faa2c5 100644
--- a/apps/docs/components/reference/enrichments/cli/CliGlobalFlagsHandler.tsx
+++ b/apps/docs/components/reference/enrichments/cli/CliGlobalFlagsHandler.tsx
@@ -1,6 +1,6 @@
import RefSubLayout from '~/layouts/ref/RefSubLayout'
-import spec from '~/spec/cli_v1_commands.yaml' assert { type: 'yaml' }
+import spec from '~/spec/cli_v1_commands.yaml' with { type: 'yaml' }
import Param from '~/components/Params'
const CliGlobalFlagsHandler = () => {
diff --git a/apps/docs/content/guides/ai/structured-unstructured.mdx b/apps/docs/content/guides/ai/structured-unstructured.mdx
index 7195197a80f..b594ae3c80e 100644
--- a/apps/docs/content/guides/ai/structured-unstructured.mdx
+++ b/apps/docs/content/guides/ai/structured-unstructured.mdx
@@ -15,7 +15,7 @@ create table docs (
id uuid primary key,
embedding vector(3),
content text,
- url string
+ url text
);
insert into docs
diff --git a/apps/docs/content/guides/auth/auth-helpers.mdx b/apps/docs/content/guides/auth/auth-helpers.mdx
index 5acfd021e85..909e15797ab 100644
--- a/apps/docs/content/guides/auth/auth-helpers.mdx
+++ b/apps/docs/content/guides/auth/auth-helpers.mdx
@@ -43,7 +43,7 @@ Working with server-side frameworks is slightly different to client-side framewo
## Status
-The Auth Helpers are in `beta`. They are usable in their current state, but it's likely that there will be breaking changes.
+The Auth Helpers are `deprecated`. Use the new `@supabase/ssr` package for Server Side Authentication. Use the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more.
## Additional links
diff --git a/apps/docs/content/guides/auth/auth-identity-linking.mdx b/apps/docs/content/guides/auth/auth-identity-linking.mdx
index ef12b12a45b..36c6dffcfd3 100644
--- a/apps/docs/content/guides/auth/auth-identity-linking.mdx
+++ b/apps/docs/content/guides/auth/auth-identity-linking.mdx
@@ -172,3 +172,13 @@ if google_identity:
+
+## Frequently asked questions
+
+### How to add email/password login to an OAuth account?
+
+Call the `updateUser({ password: 'validpassword'})` to add email with password authentication to an account created with an OAuth provider (Google, GitHub, etc.).
+
+### Can you sign up with email if already using OAuth?
+
+If you try to create an email account after previously signing up with OAuth using the same email, you'll receive an obfuscated user response with no verification email sent. This prevents user enumeration attacks.
diff --git a/apps/docs/content/guides/auth/server-side/creating-a-client.mdx b/apps/docs/content/guides/auth/server-side/creating-a-client.mdx
index 7d8e3f0ecc3..2a3f3e52f9a 100644
--- a/apps/docs/content/guides/auth/server-side/creating-a-client.mdx
+++ b/apps/docs/content/guides/auth/server-side/creating-a-client.mdx
@@ -150,9 +150,7 @@ The following code samples are for App Router. For help with Pages Router, see t
>
-```ts utils/supabase/client.tsx
-'use client'
-
+```ts utils/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
@@ -167,7 +165,7 @@ export function createClient() {
-```ts utils/supabase/server.tsx
+```ts utils/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
diff --git a/apps/docs/content/guides/auth/social-login/auth-google.mdx b/apps/docs/content/guides/auth/social-login/auth-google.mdx
index 11b24c66efd..eaa07a8ecaa 100644
--- a/apps/docs/content/guides/auth/social-login/auth-google.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-google.mdx
@@ -166,9 +166,9 @@ To use Google's pre-built signin buttons:
### Configuration [#ios-configuration]
- 1. Follow the integration instructions on the [get started with Google Sign-In](https://developers.google.com/identity/sign-in/ios/start-integrating) for iOS guide.
+ 1. Follow the integration instructions on the [get started with Google Sign-In](https://developers.google.com/identity/sign-in/ios/start-integrating) for the iOS guide.
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.
- 3. Add only the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_. Enable the `Skip nonce check` option.
+ 3. Add web client ID and iOS client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_, separated by a comma. Enable the `Skip nonce check` option.
diff --git a/apps/docs/content/guides/auth/social-login/auth-linkedin.mdx b/apps/docs/content/guides/auth/social-login/auth-linkedin.mdx
index 3e80f7dd1ce..d581605f2ef 100644
--- a/apps/docs/content/guides/auth/social-login/auth-linkedin.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-linkedin.mdx
@@ -8,12 +8,6 @@ To enable LinkedIn Auth for your project, you need to set up a LinkedIn OAuth ap
## Overview
-
-
-We will be replacing the existing _LinkedIn_ provider with a new _LinkedIn (OIDC)_ provider. Developers with LinkedIn OAuth Applications created prior to 1st August 2023 should create a new OAuth application and migrate their credentials from the _LinkedIn_ provider to the _LinkedIn (OIDC)_ provider. Alternatively, you can also add the newly released `Sign In with LinkedIn using OpenID Connect` to your existing OAuth application. [Read this section](/docs/guides/auth/social-login/auth-linkedin#linkedin-open-id-connect-oidc) to find out more.
-
-
-
Setting up LinkedIn logins for your application consists of 3 parts:
- Create and configure a LinkedIn Project and App on the [LinkedIn Developer Dashboard](https://www.linkedin.com/developers/apps).
diff --git a/apps/docs/content/guides/auth/social-login/auth-workos.mdx b/apps/docs/content/guides/auth/social-login/auth-workos.mdx
index f09fd573980..5e75b3c3e94 100644
--- a/apps/docs/content/guides/auth/social-login/auth-workos.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-workos.mdx
@@ -1,172 +1,116 @@
---
-id: 'auth-workos'
-title: 'Login with WorkOS'
-description: 'Add WorkOS OAuth to your Supabase project'
+title: 'SSO and Social Login with WorkOS'
---
-To enable WorkOS Auth for your project, you need to set up WorkOS OAuth application and add the application credentials to your Supabase Dashboard.
+## Use Social Login with WorkOS
-## Overview
+### Step 1. Create a WorkOS organization
-In this guide, we will cover how to use Supabase OAuth with WorkOS to implement Single-Sign-On(SSO).
-
-The procedure consists of five broad steps:
-
-- Create a new organization from your WorkOS Dashboard.
-- Obtain the `Client ID` from the Configuration tab and configure redirect URI.
-- Obtain the `WorkOS Secret` from the credentials tab.
-- Connect a WorkOS Supported Identity Provider
-- Add your WorkOS credentials into your Supabase project
-
-## Create a WorkOS organization
-
-Log in to the dashboard and hop over to the Organizations tab to create and organization
+Log in to the WorkOS dashboard and visit the Organizations tab to create an organization.

-## Obtain the client ID and configure redirect URI
+Alternatively, you can [create an organization via the WorkOS API](https://workos.com/docs/reference/organization/create).
-Head over to the Configuration tab and configure the redirect URI.The redirect URI should look like `https://.supabase.co/auth/v1/callback`
-Note that this is distinct from the redirect URI referred to in the Supabase dashboard
+## Step 2. Obtain your `Client ID` and `WORKOS_API_KEY` values
-
+
-## Obtain the WorkOS secret
+Visit the getting started page of the [WorkOS Dashboard](https://dashboard.workos.com/get-started). Copy the following values from the Quickstart panel:
-Head over to the API Keys page and obtain the secret key.
+- `WORKOS_CLIENT_ID`
+- `WORKOS_API_KEY`
-
+
-## Connect a WorkOS supported identity provider
+You must be signed in to see these values.
-Set up the identity provider by visiting the setup link.
+
-
+## Step 3. Add your WorkOS credentials to your Supabase project
-You can pick between any one of the many identity providers that WorkOS supports.
+
-## Add your WorkOS credentials into your Supabase project
+1. Go to your Supabase Project Dashboard.
+1. In the left sidebar, click the Authentication icon (near the top).
+1. Click on Providers under the Configuration section.
+1. Click on WorkOS from the accordion list to expand.
+1. Toggle the `WorkOS Enabled` switch to ON.
+1. Enter `https://api.workos.com` in the WorkOS URL field.
+1. Enter your WorkOS Client ID and WorkOS Client Secret saved in the previous step.
+1. Copy the `Callback URL (for OAuth)` value from the form and save it somewhere handy.
+1. Click Save.
-
+## Step 4. Set your Supabase redirect URI in the WorkOS Dashboard
-## Add login code to your client app
+Visit the WorkOS dashboard and click the redirects button in the left navigation panel.
-
-
+On the redirects page, enter your Supabase project's `Callback URL (for OAuth)` which you saved in the previous step, as shown below:
-
+
-When your user signs in, call [signInWithOAuth()](/docs/reference/javascript/auth-signinwithoauth) with `workos` as the `provider`:
+## Step 5. Add login code to your client app
-```js
+When a user signs in, call signInWithOAuth with `workos` as the provider.
+
+```javascript
async function signInWithWorkOS() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'workos',
options: {
+ redirectTo: 'http://example.com/auth/v1/callback', // Make sure your redirect URL is configured in the Supabase Dashboard Auth settings
queryParams: {
- connection: '',
- organization: '',
+ connection: '',
},
},
})
+
+ if (data.url) {
+ redirect(data.url) // use the redirect API for your server or framework
+ }
}
```
-Refer to the [WorkOS Documentation](https://workos.com/docs/reference/sso/authorize/) to learn more about the different methods.
+
-
-
+You can find your `connection_id` in the WorkOS dashboard under the Organizations tab. Select your organization and then click View connection.
-When your user signs in, call [signInWithOAuth()](/docs/reference/dart/auth-signinwithoauth) with `workos` as the `provider`:
+
-```dart
-Future signInWithWorkOS() async {
- await supabase.auth.signInWithOAuth(
- OAuthProvider.workos,
- redirectTo: kIsWeb ? null : 'my.scheme://my-host', // Optionally set the redirect link to bring back the user via deeplink.
- authScreenLaunchMode:
- kIsWeb ? LaunchMode.platformDefault : LaunchMode.externalApplication, // Launch the auth screen in a new webview on mobile.
- queryParams: {
- 'connection': '',
- 'organization': '',
- },
- );
+Within your specified callback URL, you'll exchange the code for a logged-in user profile:
+
+```javascript auth/v1/callback/route.ts
+import { NextResponse } from 'next/server'
+import { createClient } from '@/utils/supabase/server'
+
+export async function GET(request: Request) {
+ const { searchParams, origin } = new URL(request.url)
+ const code = searchParams.get('code')
+ // if "next" is in param, use it as the redirect URL
+ const next = searchParams.get('next') ?? '/'
+
+ if (code) {
+ const supabase = await createClient()
+ const { error } = await supabase.auth.exchangeCodeForSession(code)
+ if (!error) {
+ const forwardedHost = request.headers.get('x-forwarded-host') // original origin before load balancer
+ const isLocalEnv = process.env.NODE_ENV === 'development'
+ if (isLocalEnv) {
+ // we can be sure that there is no load balancer in between, so no need to watch for X-Forwarded-Host
+ return NextResponse.redirect(`${origin}${next}`)
+ } else if (forwardedHost) {
+ return NextResponse.redirect(`https://${forwardedHost}${next}`)
+ } else {
+ return NextResponse.redirect(`${origin}${next}`)
+ }
+ }
+ }
+
+ // return the user to an error page with instructions
+ return NextResponse.redirect(`${origin}/auth/auth-code-error`)
}
+
```
-Refer to the [WorkOS Documentation](https://workos.com/docs/reference/sso/authorize/) to learn more about the different methods.
-
-
-
-
-When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `WorkOS` as the `Provider`:
-
-```kotlin
-suspend fun signInWithWorkOS() {
- supabase.auth.signInWith(WorkOS) {
- queryParams["connection"] = ""
- queryParams["organization"] = ""
- queryParams["workos_provider"] = ""
- }
-}
-```
-
-Refer to the [WorkOS Documentation](https://workos.com/docs/reference/sso/authorize/) to learn more about the different methods.
-
-
-
-
-
-
-
-
-
-When your user signs out, call [signOut()](/docs/reference/javascript/auth-signout) to remove them from the browser session and any objects from localStorage:
-
-```js
-async function signOut() {
- const { error } = await supabase.auth.signOut()
-}
-```
-
-
-
-
-When your user signs out, call [signOut()](/docs/reference/dart/auth-signout) to remove them from the browser session and any objects from localStorage:
-
-```dart
-Future signOut() async {
- await supabase.auth.signOut();
-}
-```
-
-
-
-
-When your user signs out, call [signOut()](/docs/reference/kotlin/auth-signout) to remove them from the browser session and any objects from localStorage:
-
-```kotlin
-suspend fun signOut() {
- supabase.auth.signOut()
-}
-```
-
-
-
-
## Resources
- [WorkOS Documentation](https://workos.com/docs/sso/guide)
diff --git a/apps/docs/content/guides/cron/quickstart.mdx b/apps/docs/content/guides/cron/quickstart.mdx
index 874644001a4..782303b9d57 100644
--- a/apps/docs/content/guides/cron/quickstart.mdx
+++ b/apps/docs/content/guides/cron/quickstart.mdx
@@ -10,7 +10,7 @@ Attempting to create a second Job with the same name (and case) will overwrite t
-## Schedule a Job
+## Schedule a job
-## Edit a Job
+## Edit a job
-## Activate/Deactivate a Job
+## Activate/Deactivate a job
-## Unschedule a Job
+## Unschedule a job
-## Inspecting Job Runs
+## Inspecting job runs
-## Caution: Scheduling System Maintenance
+## Caution: Scheduling system maintenance
Be extremely careful when setting up Jobs for system maintenance tasks as they can have unintended consequences.
diff --git a/apps/docs/content/guides/database/connecting-to-postgres.mdx b/apps/docs/content/guides/database/connecting-to-postgres.mdx
index a8e103f3451..d866f655bf8 100644
--- a/apps/docs/content/guides/database/connecting-to-postgres.mdx
+++ b/apps/docs/content/guides/database/connecting-to-postgres.mdx
@@ -84,7 +84,7 @@ Get your project's direct string from the [Database Settings](/dashboard/project
## Supavisor session mode
-The session mode connection string connects to your Postgres instance via a proxy. This is ideal for persistent servers when IPv4 is not supported.
+The session mode connection string connects to your Postgres instance via a proxy. This is ideal for persistent servers when IPv6 is not supported.
The connection string looks like this:
diff --git a/apps/docs/content/guides/database/extensions/pg_net.mdx b/apps/docs/content/guides/database/extensions/pg_net.mdx
index eefacee9364..8855704fe94 100644
--- a/apps/docs/content/guides/database/extensions/pg_net.mdx
+++ b/apps/docs/content/guides/database/extensions/pg_net.mdx
@@ -311,7 +311,7 @@ order by "created" desc;
-Supabase supports reconfiguring pg_net starting from v0.12.0+. For the latest release, initiate a Postgres upgrade in the [Infrastructure Settings](https://supabase.com/dashboard/project/*/settings/infrastructure).
+Supabase supports reconfiguring pg*net starting from v0.12.0+. For the latest release, initiate a Postgres upgrade in the [Infrastructure Settings](https://supabase.com/dashboard/project/*/settings/infrastructure).
diff --git a/apps/docs/content/guides/database/extensions/postgis.mdx b/apps/docs/content/guides/database/extensions/postgis.mdx
index 72b85b09aff..3f96a5c9fff 100644
--- a/apps/docs/content/guides/database/extensions/postgis.mdx
+++ b/apps/docs/content/guides/database/extensions/postgis.mdx
@@ -98,9 +98,9 @@ You can insert geographical data through SQL or through our API.
insert into public.restaurants
(name, location)
values
- ('Supa Burger', st_point(-73.946823, 40.807416)),
- ('Supa Pizza', st_point(-73.94581, 40.807475)),
- ('Supa Taco', st_point(-73.945826, 40.80629));
+ ('Supa Burger', gis.st_point(-73.946823, 40.807416)),
+ ('Supa Pizza', gis.st_point(-73.94581, 40.807475)),
+ ('Supa Taco', gis.st_point(-73.945826, 40.80629));
```
diff --git a/apps/docs/content/guides/database/extensions/postgres_fdw.mdx b/apps/docs/content/guides/database/extensions/postgres_fdw.mdx
new file mode 100644
index 00000000000..2d1e6703e90
--- /dev/null
+++ b/apps/docs/content/guides/database/extensions/postgres_fdw.mdx
@@ -0,0 +1,148 @@
+---
+id: 'postgres_fdw'
+title: 'postgres_fdw'
+description: 'Query Postgres server from another'
+---
+
+The extension enables Postgres to query tables and views on a remote Postgres server.
+
+## Enable the extension
+
+
+
+
+ 1. Go to the [Database](/dashboard/project/_/database/tables) page in the Dashboard.
+ 2. Click on **Extensions** in the sidebar.
+ 3. Search for "postgres_fdw" and enable the extension.
+
+
+
+
+ ```sql
+ -- Example: enable the "postgres_fdw" extension
+ create extension if not exists postgres_fdw;
+
+ -- Example: disable the "postgres_fdw" extension
+ drop extension if exists postgres_fdw;
+ ```
+
+ Procedural languages are automatically installed within `pg_catalog`, so you don't need to specify a schema.
+
+
+
+
+
+## Create a connection to another database
+
+
+
+
+
+ Define the remote database address
+
+
+
+ ```sql
+ create server ""
+ foreign data wrapper postgres_fdw
+ options (
+ host '',
+ port '',
+ dbname ''
+ );
+ ```
+
+
+
+
+
+ Set the user credentials for the remote server
+
+
+ ```sql
+ create user mapping for ""
+ server ""
+ options (
+ user '',
+ password ''
+ );
+ ```
+
+
+
+
+
+ Import tables from the foreign database
+
+
+ Example: Import all tables from a schema
+ ```sql
+ import foreign schema ""
+ from server ""
+ into "";
+ ```
+
+ Example: Import specific tables
+ ```sql
+ import foreign schema """
+ limit to (
+ "",
+ ""
+ )
+ from server ""
+ into "";
+ ```
+
+
+
+
+
+
+ ```sql
+ select * from ''
+ ```
+
+
+
+
+
+### Configuring execution options
+
+#### Fetch_size
+
+Maximum rows fetched per operation. For example, fetching 200 rows with `fetch_size` set to 100 requires 2 requests.
+
+```sql
+alter server ""
+options (fetch_size '10000');
+```
+
+#### Batch_size
+
+Maximum rows inserted per cycle. For example, inserting 200 rows with `batch_size` set to 100 requires 2 requests.
+
+```sql
+alter server ""
+options (batch_size '1000');
+```
+
+#### Extensions
+
+Lists shared extensions. Without them, queries involving unlisted extension functions or operators may fail or omit references.
+
+```sql
+alter server ""
+options (extensions 'vector, postgis');
+```
+
+For more server options, check the extension's [official documentation](https://www.postgresql.org/docs/current/postgres-fdw.html#POSTGRES-FDW)
+
+## Resources
+
+- Official [`postgres_fdw` documentation](https://www.postgresql.org/docs/current/postgres-fdw.html#POSTGRES-FDW)
diff --git a/apps/docs/content/guides/database/functions.mdx b/apps/docs/content/guides/database/functions.mdx
index 8bf1bddc162..eb2b1a6b84e 100644
--- a/apps/docs/content/guides/database/functions.mdx
+++ b/apps/docs/content/guides/database/functions.mdx
@@ -143,7 +143,7 @@ For example, if we had a database with some Star Wars data inside:
| id | name |
| --- | -------- |
-| 1 | Tattoine |
+| 1 | Tatooine |
| 2 | Alderaan |
| 3 | Kashyyyk |
diff --git a/apps/docs/content/guides/integrations/build-a-supabase-integration.mdx b/apps/docs/content/guides/integrations/build-a-supabase-integration.mdx
index 6a09e7dbd5b..2cb88272d16 100644
--- a/apps/docs/content/guides/integrations/build-a-supabase-integration.mdx
+++ b/apps/docs/content/guides/integrations/build-a-supabase-integration.mdx
@@ -13,6 +13,8 @@ Using OAuth2.0 you can retrieve an access and refresh token that grant your appl
2. In the upper-right section of the page, click **Add application**.
3. Fill in the required details and click **Confirm**.
+{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
+
## Show a "Connect Supabase" button
In your user interface, add a "Connect Supabase" button to kick off the OAuth flow. Follow the design guidelines outlined in our [brand assets](/brand-assets).
@@ -157,7 +159,7 @@ When creating a new project, you can either ask the user to provide a database p
You can configure the user's [custom SMTP settings](https://supabase.com/docs/guides/auth/auth-smtp) using the [`/config/auth` endpoint](https://api.supabase.com/api/v1#/projects%20config/updateV1AuthConfig).
-### Handling Dynamic Redirect URLs
+### Handling dynamic redirect URLs
To handle multiple, dynamically generated redirect URLs within the same OAuth app, you can leverage the `state` query parameter. When starting the OAuth process, include the desired, encoded redirect URL in the `state` parameter.
Once authorization is complete, we will sends the `state` value back to your app. You can then verify its integrity and extract the correct redirect URL, decoding it and redirecting the user to the correct URL.
diff --git a/apps/docs/content/guides/integrations/vercel-marketplace.mdx b/apps/docs/content/guides/integrations/vercel-marketplace.mdx
index ec92cffa11c..5821eeccb07 100644
--- a/apps/docs/content/guides/integrations/vercel-marketplace.mdx
+++ b/apps/docs/content/guides/integrations/vercel-marketplace.mdx
@@ -20,7 +20,7 @@ Vercel Marketplace is currently in Public Alpha. If you encounter any issues or
## Quickstart
-### Via Template
+### Via template
Deploy a Next.js app with Supabase Vercel Storage now
@@ -34,7 +34,7 @@ Vercel Marketplace is currently in Public Alpha. If you encounter any issues or
Details coming soon..
-### Connecting to Supabase Project
+### Connecting to Supabase project
Supabase Projects created via Vercel Marketplace are automatically synchronized with connected Vercel projects. This synchronization includes setting essential environment variables, such as:
diff --git a/apps/docs/content/guides/local-development.mdx b/apps/docs/content/guides/local-development.mdx
index 06ac6119d8e..49d0bed8ec0 100644
--- a/apps/docs/content/guides/local-development.mdx
+++ b/apps/docs/content/guides/local-development.mdx
@@ -97,7 +97,7 @@ Develop locally while running the Supabase stack on your machine.
4. View your local Supabase instance at [http://localhost:54323](http://localhost:54323).
-## Local Development
+## Local development
Local development with Supabase allows you to work on your projects in a self-contained environment on your local machine. Working locally has several advantages:
diff --git a/apps/docs/content/guides/monitoring-troubleshooting/advanced-log-filtering.mdx b/apps/docs/content/guides/monitoring-troubleshooting/advanced-log-filtering.mdx
index 2097c3d163a..e3e81cad023 100644
--- a/apps/docs/content/guides/monitoring-troubleshooting/advanced-log-filtering.mdx
+++ b/apps/docs/content/guides/monitoring-troubleshooting/advanced-log-filtering.mdx
@@ -129,7 +129,7 @@ regexp_contains(event_message, 'hello world\.')
regexp_contains(event_message, 'started host|authenticated')
```
-### and/or/not statements in SQL:
+### `and`/`or`/`not` statements in SQL:
`and`, `or`, and `not` are all native terms in SQL and can be used in conjunction with regular expressions to filter results
diff --git a/apps/docs/content/guides/monitoring-troubleshooting/exhaust-cpu.mdx b/apps/docs/content/guides/monitoring-troubleshooting/exhaust-cpu.mdx
index b056ec150d2..9f3bd379e4d 100644
--- a/apps/docs/content/guides/monitoring-troubleshooting/exhaust-cpu.mdx
+++ b/apps/docs/content/guides/monitoring-troubleshooting/exhaust-cpu.mdx
@@ -39,4 +39,4 @@ Everything you do with your Supabase project requires compute. Hence, there can
There are two ways to solve high CPU:
1. **Optimize performance:** Get more out of your instance's resources by optimizing your usage. Have a look at our [performance tuning guide](https://supabase.com/docs/guides/platform/performance#examining-query-performance) and our [production readiness guide](https://supabase.com/docs/guides/platform/going-into-prod#performance).
-2. **Upgrade your compute:** You can get a Compute Add-on for your project. Follow [this link](https://supabase.com/dashboard/project/_/settings/addons?panel=computeInstance) and select your project to see your upgrade options.
+2. **Upgrade your compute:** You can get a Compute Add-on for your project. Follow [this link](https://supabase.com/dashboard/project/_/settings/compute-and-disk) and select your project to see your upgrade options.
diff --git a/apps/docs/content/guides/monitoring-troubleshooting/exhaust-disk-io.mdx b/apps/docs/content/guides/monitoring-troubleshooting/exhaust-disk-io.mdx
index 28e5e98b3d6..8e48f668237 100644
--- a/apps/docs/content/guides/monitoring-troubleshooting/exhaust-disk-io.mdx
+++ b/apps/docs/content/guides/monitoring-troubleshooting/exhaust-disk-io.mdx
@@ -37,5 +37,5 @@ Most operations on your Supabase project require disk IO in some form. Hence, th
## How to fix
-1. **Upgrade your compute:** You can get a Compute Add-on for your project. See your [upgrade options](https://supabase.com/dashboard/project/_/settings/addons?panel=computeInstance) by selecting your project. Do reference the [different baseline performances](https://supabase.com/docs/guides/platform/compute-add-ons#disk-io) that come with larger Compute Add-ons.
+1. **Upgrade your compute:** You can get a Compute Add-on for your project. See your [upgrade options](https://supabase.com/dashboard/project/_/settings/compute-and-disk) by selecting your project. Do reference the [different baseline performances](https://supabase.com/docs/guides/platform/compute-add-ons#disk-io) that come with larger Compute Add-ons.
2. **Optimize performance:** Get more out of your instance's resources by optimizing your usage. Have a look at our [performance tuning guide](https://supabase.com/docs/guides/platform/performance#examining-query-performance) and our [production readiness guide](https://supabase.com/docs/guides/platform/going-into-prod#performance).
diff --git a/apps/docs/content/guides/monitoring-troubleshooting/exhaust-ram.mdx b/apps/docs/content/guides/monitoring-troubleshooting/exhaust-ram.mdx
index 12381f9d492..e82c0f25aae 100644
--- a/apps/docs/content/guides/monitoring-troubleshooting/exhaust-ram.mdx
+++ b/apps/docs/content/guides/monitoring-troubleshooting/exhaust-ram.mdx
@@ -44,5 +44,5 @@ Everything you do with your Supabase project requires memory in some form. Hence
## How to fix your memory issues
-1. **Upgrade your compute:** You can get a Compute Add-on for your project. See your [upgrade options](https://supabase.com/dashboard/project/_/settings/addons?panel=computeInstance) by selecting your project.
+1. **Upgrade your compute:** You can get a Compute Add-on for your project. See your [upgrade options](https://supabase.com/dashboard/project/_/settings/compute-and-disk) by selecting your project.
2. **Optimize performance:** Get more out of your instance's resources by optimizing your usage. Have a look at our [performance tuning guide](https://supabase.com/docs/guides/platform/performance#examining-query-performance) and our [production readiness guide](https://supabase.com/docs/guides/platform/going-into-prod#performance).
diff --git a/apps/docs/content/guides/monitoring-troubleshooting/exhaust-swap.mdx b/apps/docs/content/guides/monitoring-troubleshooting/exhaust-swap.mdx
index 247e9466d36..ae4125cacf7 100644
--- a/apps/docs/content/guides/monitoring-troubleshooting/exhaust-swap.mdx
+++ b/apps/docs/content/guides/monitoring-troubleshooting/exhaust-swap.mdx
@@ -6,7 +6,7 @@ description: 'Learn what high Swap usage could mean for your Supabase instance a
Learn what high Swap usage means, what can cause it, and how to solve it.
-## What is Swap for?
+## What is swap for?
@@ -20,7 +20,7 @@ Swap is a portion of your instance's disk that is reserved for the operating sys
Swap can be used even if your instance has plenty of RAM. If this is the case, do not worry. Your instance might try to "preemptively swap" by swapping background processes to make space for your traffic in RAM.
-### When is high Swap concerning?
+### When is high swap concerning?
High Swap is concerning if your instance is using all of the available RAM (i.e. consistently using more than 75%).
@@ -30,7 +30,7 @@ High Swap usage can affect your database performance. For example, you might see
- **Degraded performance due to swapping regularly between RAM and disk.**
- **Higher Disk I/O due to swapping regularly.**
-## Monitor your Swap
+## Monitor your swap
You can check your Swap usage directly on the Supabase Platform. Navigate to the [**Database** page](https://supabase.com/dashboard/project/_/reports/database) of the **Reports** section.
@@ -45,7 +45,7 @@ Some useful metrics to monitor are (this is not an exhaustive list):
- `node_memory_MemTotal_bytes` and `node_memory_MemFree_bytes` - The total RAM and available RAM.
- `node_vmstat_pswpin` and `node_vmstat_pswpout` - The number of pages that have been swapped in or out (monitoring this for spikes means that your instance is swapping).
-## Common reasons for high Swap usage
+## Common reasons for high swap usage
Everything you do with your Supabase project requires compute. Hence, there can be many reasons for high Swap usage. Here are some common ones:
@@ -55,10 +55,10 @@ Everything you do with your Supabase project requires compute. Hence, there can
- **Workload style:** The usage pattern of your Supabase project might be more read heavy, or involve large amounts of data.
- **Extensions:** You might be using extensions that perform intensive operations on large datasets. This increases resource usage.
-## Solving high Swap usage
+## Solving high swap usage
If you find that your RAM and Swap usage are high, you have three options:
1. **Optimize performance:** Get more out of your instance's resources by optimizing your usage. See the [performance tuning guide](https://supabase.com/docs/guides/platform/performance#examining-query-performance) and our [production readiness guide](https://supabase.com/docs/guides/platform/going-into-prod#performance).
-2. **Upgrade your compute:** You can get a Compute Add-on for your project. Navigate to [the **Addons** section in project settings](https://supabase.com/dashboard/project/_/settings/addons?panel=computeInstance) to see your upgrade options.
+2. **Upgrade your compute:** You can get a Compute Add-on for your project. Follow [this link](https://supabase.com/dashboard/project/_/settings/compute-and-disk) and select your project to see your upgrade options.
3. **Read Replicas:** You can spread the load on your Supabase project by creating a Read Replica. See [the read replicas guide](https://supabase.com/docs/guides/platform/read-replicas) for more information.
diff --git a/apps/docs/content/guides/monitoring-troubleshooting/http-status-codes.mdx b/apps/docs/content/guides/monitoring-troubleshooting/http-status-codes.mdx
index 5dcfec6e635..d86a6bb6597 100644
--- a/apps/docs/content/guides/monitoring-troubleshooting/http-status-codes.mdx
+++ b/apps/docs/content/guides/monitoring-troubleshooting/http-status-codes.mdx
@@ -51,6 +51,6 @@ The request is not completed within the configured time limit.
The timeout limit is set to prevent long-running queries which can cause performance issues, increase latency, and potentially even crash the project.
-#### 546 Edge Functions Resource Limit
+#### 546 Edge Functions resource limit
Applies only to Edge Functions. Function execution was stopped due to a resource limit (`WORKER_LIMIT`). Edge Function logs should provide which [resource limit](/guides/functions/limits) was exceeded.
diff --git a/apps/docs/content/guides/monitoring-troubleshooting/log-drains.mdx b/apps/docs/content/guides/monitoring-troubleshooting/log-drains.mdx
index f2f508f581e..0cd85cca823 100644
--- a/apps/docs/content/guides/monitoring-troubleshooting/log-drains.mdx
+++ b/apps/docs/content/guides/monitoring-troubleshooting/log-drains.mdx
@@ -8,7 +8,7 @@ Log drains will send all logs of the Supabase stack to one or more desired desti
You can read about the initial announcement [here](https://supabase.com/blog/log-drains) and vote for your preferred drains in [this discussion](https://github.com/orgs/supabase/discussions/28324?sort=top).
-# Supported Destinations
+# Supported destinations
The following table lists the supported destinations and the required setup configuration:
@@ -19,7 +19,7 @@ The following table lists the supported destinations and the required setup conf
HTTP requests are batched with a max of 250 logs or 1 second intervals, whichever happens first. Logs are compressed via Gzip if the destination supports it.
-## Generic HTTP Endpoint
+## Generic HTTP endpoint
Logs are sent as a POST request with a JSON body. Both HTTP/1 and HTTP/2 protocols are supported.
Custom headers can optionally be configured for all requests.
@@ -132,7 +132,7 @@ Deno.serve(async (req) => {
-## Datadog Logs
+## Datadog logs
Logs sent to Datadog have the name of the log source set on the `service` field of the event and the source set to `Supabase`. Logs are gzipped before they are sent to Datadog.
diff --git a/apps/docs/content/guides/monitoring-troubleshooting/troubleshooting.mdx b/apps/docs/content/guides/monitoring-troubleshooting/troubleshooting.mdx
index 485a2f4efee..bbb71cf897b 100644
--- a/apps/docs/content/guides/monitoring-troubleshooting/troubleshooting.mdx
+++ b/apps/docs/content/guides/monitoring-troubleshooting/troubleshooting.mdx
@@ -24,7 +24,7 @@ You can view the resource utilization of your Supabase Project using the [report
Some common solutions for this issue are:
-- [Upgrading](https://supabase.com/dashboard/project/_/settings/addons?panel=computeInstance) to a [larger compute add-on](../platform/compute-add-ons) in order to serve higher volumes of traffic.
+- [Upgrading](https://supabase.com/dashboard/project/_/settings/compute-and-disk) to a [larger compute add-on](../platform/compute-add-ons) in order to serve higher volumes of traffic.
- [Optimizing the queries](../platform/performance#examining-query-performance) being executed.
- [Using fewer Postgres connections](../platform/performance#configuring-clients-to-use-fewer-connections) can reduce the amount of resources needed on the project.
- [Restarting](https://supabase.com/dashboard/project/_/settings/general) the project. This only temporarily solves the issue by terminating any ongoing workloads that might be tying up your compute resources.
@@ -43,7 +43,7 @@ Errors about too many open connections can be _temporarily_ resolved by [restart
- If you're receiving a `No more connections allowed (max_client_conn)` error:
- Configure your applications and services to [use fewer connections](../platform/performance#configuring-clients-to-use-fewer-connections).
- - [Upgrade](https://supabase.com/dashboard/project/_/settings/addons?panel=computeInstance) to a [larger compute add-on](../platform/compute-add-ons) to increase the number of available connections.
+ - [Upgrade](https://supabase.com/dashboard/project/_/settings/compute-and-disk) to a [larger compute add-on](../platform/compute-add-ons) to increase the number of available connections.
- If you're receiving a `sorry, too many clients already` or `remaining connection slots are reserved for non-replication superuser connections` error message in addition to the above suggestions, switch to using the [connection pooler](/docs/guides/database/connecting-to-postgres#connection-pool) instead.
### Connection refused
diff --git a/apps/docs/content/guides/platform/access-control.mdx b/apps/docs/content/guides/platform/access-control.mdx
index dcc277294c2..e0ed0f6a5e1 100644
--- a/apps/docs/content/guides/platform/access-control.mdx
+++ b/apps/docs/content/guides/platform/access-control.mdx
@@ -38,7 +38,7 @@ Each Supabase organization must have at least one owner. If your organization ha
Otherwise, you'll need to invite a user as **Owner**, and they need to accept the invitation, or promote an existing organization member to **Owner** before you can leave the organization.
-### Organization Scoped Roles vs Project Scoped Roles
+### Organization scoped roles vs project scoped roles
diff --git a/apps/docs/content/guides/platform/backups.mdx b/apps/docs/content/guides/platform/backups.mdx
index c6c413027b6..abd12808510 100644
--- a/apps/docs/content/guides/platform/backups.mdx
+++ b/apps/docs/content/guides/platform/backups.mdx
@@ -168,13 +168,19 @@ Once the restoration is complete, the new project will be available in your dash
New projects are completely independent of their source, and as such can be modified and used as desired.
+
+
+As the entire database is copied to the new project, this will include all extensions that were enabled at the source. If the source project included extensions that are configured to carry out external operations—for example pg_net, pg_cron, wrappers—these should be disabled once the copy process has completed to avoid any unwanted actions from taking place.
+
+
+
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
-#### search_path issues
+#### `search_path` issues
During the `pg_restore` process, the `search_path` is set to an empty string for predictability, and security. Using unqualified references to functions or relations can cause restorations using logical backups to fail, as the database will not be able to locate the function or relation being referenced. This can happen even if the database functions without issues during normal operations, as the `search_path` is usually set to include several schemas during normal operations. Therefore, you should always use schema-qualified names within your SQL code.
diff --git a/apps/docs/content/guides/platform/compute-and-disk.mdx b/apps/docs/content/guides/platform/compute-and-disk.mdx
index 74aeec43fef..5f8f57bd6c0 100644
--- a/apps/docs/content/guides/platform/compute-and-disk.mdx
+++ b/apps/docs/content/guides/platform/compute-and-disk.mdx
@@ -94,7 +94,7 @@ Smaller compute instances like Nano, Micro, and Small have baseline performance
If you need consistent disk performance, choose the 4XL or larger compute instance. If you're unsure of how much throughput or IOPS your application requires, you can load test your project and inspect these [metrics in the Dashboard](https://supabase.com/dashboard/project/_/reports). If the `Disk IO % consumed` stat is more than 1%, it indicates that your workload has exceeded the baseline IO throughput during the day. If this metric goes to 100%, the workload has used up all available disk IO budget. Projects that use any disk IO budget are good candidates for upgrading to a larger compute instance with higher throughput.
-### Provisioned Disk throughput and IOPS
+### Provisioned disk throughput and IOPS
The default disk type is gp3, which comes with a baseline throughput of 125 MiB/s and a default IOPS of 3,000. You can provision additional IOPS and throughput from the [Database Settings](/dashboard/project/_/settings/database) page, but keep in mind that the effective IOPS and throughput will be limited by the compute instance size.
@@ -130,7 +130,7 @@ Compute instance size changes will not change your selected disk type or disk si
- General Purpose (gp3) disks come with a baseline of 3,000 IOPS and 125 MiB/s. You can provision additional 500 IOPS for every GB of disk size and additional 0.25 MiB/s throughput per provisioned IOPS.
- High Performance (io2) disks can be provisioned with 1,000 IOPS per GB of disk size.
-## Limits and Constraints
+## Limits and constraints
### Postgres replication slots, WAL senders, and connections
diff --git a/apps/docs/content/guides/platform/database-size.mdx b/apps/docs/content/guides/platform/database-size.mdx
index a4774aa07a0..adcf8937c30 100644
--- a/apps/docs/content/guides/platform/database-size.mdx
+++ b/apps/docs/content/guides/platform/database-size.mdx
@@ -139,7 +139,7 @@ Once you have reclaimed space, you can run the following to disable [read-only](
set default_transaction_read_only = 'off';
```
-### Disk Size Distribution
+### 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).
diff --git a/apps/docs/content/guides/platform/hipaa-projects.mdx b/apps/docs/content/guides/platform/hipaa-projects.mdx
new file mode 100644
index 00000000000..b5e9a92470a
--- /dev/null
+++ b/apps/docs/content/guides/platform/hipaa-projects.mdx
@@ -0,0 +1,28 @@
+---
+id: 'hipaa'
+title: 'HIPAA Projects'
+description: 'Projects that store or process Protected Health Information (PHI) and other sensitive data'
+---
+
+You can use Supabase to store and process Protected Health Information (PHI). If you want to start developing healthcare apps on Supabase, reach out to the Supabase team [here](https://forms.supabase.com/hipaa2) to sign the Business Associate Agreement (BAA).
+
+
+
+Organizations must have a signed BAA with Supabase and have the Health Insurance Portability and Accountability Act (HIPAA) add-on enabled when dealing with PHI.
+
+
+
+## Configuring a HIPAA project
+
+When the HIPAA add-on is enabled on an organization, projects within the organization can be configured as _High Compliance_. This configuration can be found in the [General Project Settings page](https://supabase.com/dashboard/project/_/settings) of the dashboard.
+Once enabled, additional security checks will be run against the project to ensure the deployed configuration is compliant. These checks are performed on a continual basis and security warnings will appear in the [Security Advisor](https://supabase.com/dashboard/project/_/advisors/security) if a non-compliant setting is detected.
+
+The required project configuration is outlined in the [shared responsibility model](https://supabase.com/docs/guides/deployment/shared-responsibility-model#managing-healthcare-data) for managing healthcare data.
+
+These include:
+
+- Enabling [Point in Time Recovery](/docs/guides/platform/backups#point-in-time-recovery) which requires at least a [small compute add-on](/docs/guides/platform/compute-add-ons).
+- Turning on [SSL Enforcement](/docs/guides/platform/ssl-enforcement).
+- Enabling [Network Restrictions](/docs/guides/platform/network-restrictions).
+
+Additional security checks and controls will be added as the security advisor is extended and additional security controls are made available.
diff --git a/apps/docs/content/guides/platform/migrating-to-supabase/firebase-auth.mdx b/apps/docs/content/guides/platform/migrating-to-supabase/firebase-auth.mdx
index bf2687b7a10..b29d4396844 100644
--- a/apps/docs/content/guides/platform/migrating-to-supabase/firebase-auth.mdx
+++ b/apps/docs/content/guides/platform/migrating-to-supabase/firebase-auth.mdx
@@ -69,7 +69,7 @@ hash_config {
- `filename.json`: (optional) output filename (defaults to `./users.json`)
- `batchSize`: (optional) number of users to fetch in each batch (defaults to 100)
-### Import JSON users file to Supabase Auth (Postgres: auth.users) [#import-json-users-file]
+### Import JSON users file to Supabase Auth (Postgres: `auth.users`) [#import-json-users-file]
`node import_users.js []`
diff --git a/apps/docs/content/guides/platform/migrating-to-supabase/neon.mdx b/apps/docs/content/guides/platform/migrating-to-supabase/neon.mdx
index 8a983829a5d..b8cfd9fd095 100644
--- a/apps/docs/content/guides/platform/migrating-to-supabase/neon.mdx
+++ b/apps/docs/content/guides/platform/migrating-to-supabase/neon.mdx
@@ -19,7 +19,7 @@ Example:
postgresql://neondb_owner:xxxxxxxxxxxxxxx-random-word-yyyyyyyy.us-west-2.aws.neon.tech/neondb?sslmode=require
```
-## Set your OLD_DB_URL environment variable
+## Set your `OLD_DB_URL` environment variable
Set the **OLD_DB_URL** environment variable at the command line using your Neon database credentials from the clipboard.
@@ -38,7 +38,7 @@ export OLD_DB_URL="postgresql://neondb_owner:xxxxxxxxxxxxxxx-random-word-yyyyyyy
1. Under **Connection string**, select **URI**, make sure **Display connection pooler** is checked, and **Mode: Session** is set.
1. Click the **Copy** button to the right of your connection string to copy it to the clipboard.
-## Set your NEW_DB_URL environment variable
+## Set your `NEW_DB_URL` environment variable
Set the **NEW_DB_URL** environment variable at the command line using your Supabase connection string. You will need to replace `[YOUR-PASSWORD]` with your actual database password.
diff --git a/apps/docs/content/guides/platform/migrating-to-supabase/vercel-postgres.mdx b/apps/docs/content/guides/platform/migrating-to-supabase/vercel-postgres.mdx
index a94bfaf697f..d3207cbd34f 100644
--- a/apps/docs/content/guides/platform/migrating-to-supabase/vercel-postgres.mdx
+++ b/apps/docs/content/guides/platform/migrating-to-supabase/vercel-postgres.mdx
@@ -26,7 +26,7 @@ Copy this part to your clipboard:
"postgres://default:xxxxxxxxxxxx@yy-yyyyy-yyyyyy-yyyyyyy.us-west-2.aws.neon.tech:5432/verceldb?sslmode=require"
```
-## Set your OLD_DB_URL environment variable
+## Set your `OLD_DB_URL` environment variable
Set the **OLD_DB_URL** environment variable at the command line using your Vercel Postgres Database credentials.
@@ -45,7 +45,7 @@ export OLD_DB_URL="postgres://default:xxxxxxxxxxxx@yy-yyyyy-yyyyyy-yyyyyyy.us-we
1. Under **Connection string**, select **URI**, make sure **Display connection pooler** is checked, and **Mode: Session** is set.
1. Click the **Copy** button to the right of your connection string to copy it to the clipboard.
-## Set your NEW_DB_URL environment variable
+## Set your `NEW_DB_URL` environment variable
Set the **NEW_DB_URL** environment variable at the command line using your Supabase connection string. You will need to replace `[YOUR-PASSWORD]` with your actual database password.
diff --git a/apps/docs/content/guides/platform/org-based-billing.mdx b/apps/docs/content/guides/platform/org-based-billing.mdx
index 60151a8cbfa..ef394ebe867 100644
--- a/apps/docs/content/guides/platform/org-based-billing.mdx
+++ b/apps/docs/content/guides/platform/org-based-billing.mdx
@@ -90,7 +90,7 @@ We only count compute hours for instances that are active. Paused projects do no
| 12XL | $3.836 | ~$2800 |
| 16XL | $5.12 | ~$3730 |
-### Compute Credits
+### Compute credits
Paid plans come with $10 of Compute Credits to cover one Micro instance or parts of any other [Compute Add-On](/docs/guides/platform/compute-add-ons).
@@ -153,7 +153,7 @@ You can see a breakdown of the different types of egress on your [organization u
/>
-## Disk Size
+## Disk size
We differentiate between database space usage and disk size. Database Space is the actual amount of space used by all your database objects, whereas disk size is the size of the underlying provisioned disk. Each database has a provisioned disk.
@@ -178,7 +178,7 @@ Supabase provides two "Free projects". Each project can run a `Nano` instance fo
We count your total limit of 2 free projects across all organizations you're either an Owner or Administrator of. You could have two Free Plan organizations with one project each, or one Free Plan organization with two projects. Paused projects do not count towards your free project limit.
-## Billing Examples
+## Billing examples
Here are some examples on how the Billing affects you.
diff --git a/apps/docs/content/guides/platform/performance.mdx b/apps/docs/content/guides/platform/performance.mdx
index cac8f7005d5..8b2f4a85164 100644
--- a/apps/docs/content/guides/platform/performance.mdx
+++ b/apps/docs/content/guides/platform/performance.mdx
@@ -150,7 +150,7 @@ from pg_statio_user_tables;
This shows the ratio of data blocks fetched from the Postgres [shared_buffers](https://www.postgresql.org/docs/15/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-MEMORY) cache against the data blocks that were read from disk/OS cache.
-If either of your index or table hit rate are < 99% then this can indicate your compute plan is too small for your current workload and you would benefit from more memory. [Upgrading your compute](./compute-add-ons) is easy and can be done from your [project dashboard](https://supabase.com/dashboard/project/_/settings/addons?panel=computeInstance).
+If either of your index or table hit rate are < 99% then this can indicate your compute plan is too small for your current workload and you would benefit from more memory. [Upgrading your compute](./compute-add-ons) is easy and can be done from your [project dashboard](https://supabase.com/dashboard/project/_/settings/compute-and-disk).
### Optimizing poor performing queries
@@ -186,7 +186,7 @@ FATAL: remaining connection slots are reserved for non-replication superuser con
In such a scenario, you can consider:
-- [upgrading to a larger compute add-on](https://supabase.com/dashboard/project/_/settings/addons?panel=computeInstance)
+- [upgrading to a larger compute add-on](https://supabase.com/dashboard/project/_/settings/compute-and-disk)
- configuring your clients to use fewer connections
- manually configuring the database for a higher number of connections
diff --git a/apps/docs/content/guides/platform/read-replicas.mdx b/apps/docs/content/guides/platform/read-replicas.mdx
index 755574005b8..56540f30af8 100644
--- a/apps/docs/content/guides/platform/read-replicas.mdx
+++ b/apps/docs/content/guides/platform/read-replicas.mdx
@@ -60,6 +60,8 @@ A Read Replica is deployed by using a physical backup as a starting point, and a
Along with the progress of the deployment, the dashboard displays rough estimates for each component.
+{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
+
### What does it mean when "Init failed" is observed?
The status `Init failed` indicates that the Read Replica has failed to deploy. Some possible scenarios as to why a Read Replica may have failed to be deployed:
diff --git a/apps/docs/content/guides/platform/sso/azure.mdx b/apps/docs/content/guides/platform/sso/azure.mdx
index a4f08432c01..5a23c9a9c98 100644
--- a/apps/docs/content/guides/platform/sso/azure.mdx
+++ b/apps/docs/content/guides/platform/sso/azure.mdx
@@ -25,7 +25,7 @@ Click the _Add_ button then _Enterprise application_.

-## Step 2: Choose Create your own application [#create-application]
+## Step 2: Choose to create your own application [#create-application]
You'll be using the custom enterprise application setup for Supabase.
@@ -40,7 +40,7 @@ don't find in the gallery (Non-gallery)_.

-## Step 4: Choose the Set up single sign-on option [#set-up-single-sign-on]
+## Step 4: Set up single sign-on [#set-up-single-sign-on]
Before you get to assigning users and groups, which would allow accounts in Azure AD to access Supabase, you need to configure the SAML details that allows Supabase to accept sign in requests from Azure AD.
diff --git a/apps/docs/content/guides/platform/sso/gsuite.mdx b/apps/docs/content/guides/platform/sso/gsuite.mdx
index e20a1140660..fbeeb299a63 100644
--- a/apps/docs/content/guides/platform/sso/gsuite.mdx
+++ b/apps/docs/content/guides/platform/sso/gsuite.mdx
@@ -21,7 +21,7 @@ Supabase supports single sign-on (SSO) using Google Workspace (formerly known as

-## Step 2: Choose Add custom SAML app [#add-custom-saml-app]
+## Step 2: Choose to add custom SAML app [#add-custom-saml-app]
From the _Add app_ button in the toolbar choose _Add custom SAML app_.
diff --git a/apps/docs/content/guides/platform/sso/okta.mdx b/apps/docs/content/guides/platform/sso/okta.mdx
index 78cce43d336..116a0995d80 100644
--- a/apps/docs/content/guides/platform/sso/okta.mdx
+++ b/apps/docs/content/guides/platform/sso/okta.mdx
@@ -17,7 +17,7 @@ Looking for docs on how to add Single Sign-On support in your Supabase project?
Supabase supports single sign-on (SSO) using Okta.
-## Step 1: Choose Create App Integration in the Applications dashboard [#create-app-integration]
+## Step 1: Choose to create an app integration in the applications dashboard [#create-app-integration]
Navigate to the Applications dashboard of the Okta admin console. Click _Create App Integration_.
@@ -29,13 +29,13 @@ Supabase supports the SAML 2.0 SSO protocol. Choose it from the _Create a new ap

-## Step 3: Fill out General Settings [#add-general-settings]
+## Step 3: Fill out general settings [#add-general-settings]
The information you enter here is for visibility into your Okta applications menu. You can choose any values you like. `Supabase` as a name works well for most use cases.

-## Step 4: Fill out SAML Settings [#add-saml-settings]
+## Step 4: Fill out SAML settings [#add-saml-settings]
These settings let Supabase use SAML 2.0 properly with your Okta application. Make sure you enter this information exactly as shown on in this table and screenshot.
@@ -51,7 +51,7 @@ These settings let Supabase use SAML 2.0 properly with your Okta application. Ma

-## Step 5: Fill out Attribute Statements [#add-attribute-statements]
+## Step 5: Fill out attribute statements [#add-attribute-statements]
Attribute Statements allow Supabase to get information about your Okta users on each login.
diff --git a/apps/docs/content/guides/platform/upgrading.mdx b/apps/docs/content/guides/platform/upgrading.mdx
index 1bdab44de90..b7ab96b76a3 100644
--- a/apps/docs/content/guides/platform/upgrading.mdx
+++ b/apps/docs/content/guides/platform/upgrading.mdx
@@ -70,7 +70,7 @@ Breaking changes are generally only present in major version upgrades of Postgre
If you are upgrading from a significantly older version, you will need to consider the release notes for any intermediary releases as well.
-#### Time Limits
+#### Time limits
Starting from 2024-06-24, when a project is paused, users then have a 90-day window to restore the project on the platform from within Supabase Studio.
@@ -100,7 +100,7 @@ If you upgrade to a paid plan while your project is paused, any expired one-clic
src="/docs/img/guides/platform/paused-paid-tier.png"
/>
-#### Restoring a Downloaded Backup Locally
+#### Restoring a downloaded backup locally
If the 90 day project restore window has expired but you need to access data contained within your project using SQL, you can attempt to restore the project into a local Postgres instance. Supabase publishes tooling that can be used for that purpose. Be aware that this workflow does not produce a complete Supabase environment with REST/Auth/Storage. Instead, it creates a standalone Postgres instance that is maximally compatible with your project's backup file to assist with recovering your data.
@@ -157,7 +157,7 @@ When upgrading, the Supabase platform will "right-size" your disk based on the c
pg_upgrade does not support upgrading of databases containing reg\* data types referencing system OIDs.
If you have created any objects that depend on the following extensions, you will need to recreate them after the upgrade.
-#### pg_cron records
+#### `pg_cron` records
[pg_cron](https://github.com/citusdata/pg_cron#viewing-job-run-details) does not automatically clean up historical records. This can lead to extremely large `cron.job_run_details` tables if the records are not regularly pruned; you should clean unnecessary records from this table prior to an upgrade.
diff --git a/apps/docs/content/guides/queues/quickstart.mdx b/apps/docs/content/guides/queues/quickstart.mdx
index 426f057ea6c..6743a6cafe6 100644
--- a/apps/docs/content/guides/queues/quickstart.mdx
+++ b/apps/docs/content/guides/queues/quickstart.mdx
@@ -18,7 +18,7 @@ A pull-based Queue is a Message storage and delivery system where consumers acti
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
+### Queue types
Supabase Queues offers three types of Queues:
@@ -141,7 +141,7 @@ The permissions required for each Queue API database function:
-### Enqueuing and Dequeuing Messages
+### Enqueuing and dequeuing messages
Once your Queue has been created, you can begin enqueuing and dequeuing Messages.
diff --git a/apps/docs/content/guides/realtime/benchmarks.mdx b/apps/docs/content/guides/realtime/benchmarks.mdx
new file mode 100644
index 00000000000..9a12182df42
--- /dev/null
+++ b/apps/docs/content/guides/realtime/benchmarks.mdx
@@ -0,0 +1,153 @@
+---
+title: 'Benchmarks'
+subtitle: 'Benchmark results for Supabase Realtime.'
+description: 'Check out reference numbers for Supabase Realtime performance.'
+---
+
+This guide explores what can be expected from Realtime's Postgres Changes, broadcast and presence performance. A set of load tests demonstrates its scaling capabilities.
+
+## Methodology
+
+The benchmarks were conducted using k6, an open-source load testing tool, against a Realtime Cluster deployed on AWS. The cluster configurations used 2-6 nodes, tested in both single-region and multi-region setups, all connected to a single Supabase project. The load generators (k6 servers) were also deployed on AWS to minimize network latency impact on the results. Tests were executed with the full load from the start without warm-up runs.
+
+The metrics collected include message throughput, latency percentiles, CPU and memory utilization, and connection success rates. It's worth noting that performance in production environments may vary based on factors such as network conditions, hardware specifications, and specific usage patterns.
+
+## Workloads
+
+The proposed workloads are designed to demonstrate Supabase Realtime's throughput and scalability capabilities. These benchmarks focus on core functionality and common usage patterns.
+
+The benchmarking results include the following workloads:
+
+1. **Broadcast Performance**
+2. **Payload Size Impact on Broadcast**
+3. **Large-Scale Broadcasting**
+4. **Authentication and New Connection Rate**
+5. **Database Events**
+
+## Results
+
+### Realtime Broadcast Performance
+
+This workload evaluates the system's capacity to handle multiple concurrent WebSocket connections and message broadcasting. Each virtual user (VU) in the test:
+
+- Establishes and maintains a WebSocket connection
+- Joins two distinct channels:
+ - An echo channel (1 user per channel) for direct message reflection
+ - A broadcast channel (6 users per channel) for group communication
+- Generates traffic by sending 2 messages per second to each joined channel for 10 minutes
+
+
+
+| Metric | Value |
+| ------------------- | ------------------------- |
+| Concurrent Users | 32_000 |
+| Total Channel Joins | 64_000 |
+| Message Throughput | 224_000 msgs/sec |
+| Median Latency | 6 ms |
+| Latency (p95) | 28 ms |
+| Latency (p99) | 213 ms |
+| Data Received | 47.2 MB/s (29.6 GB total) |
+| Data Sent | 15.2 MB/s (9.6 GB total) |
+| New Connection Rate | 320 conn/sec |
+| Channel Join Rate | 640 joins/sec |
+
+### Payload Size Impact
+
+This workload tests the system's performance with different message payload sizes to understand how data volume affects throughput and latency. Each virtual user (VU) follows the same connection pattern as the broadcast test, but with varying message sizes:
+
+- Establishes and maintains a WebSocket connection
+- Joins two distinct channels:
+ - An echo channel (1 user per channel) for direct message reflection
+ - A broadcast channel (6 users per channel) for group communication
+- Sends messages with payloads of 1KB, 10KB, and 50KB
+- Generates traffic by sending 2 messages per second to each joined channel for 5 minutes
+
+#### 1KB Payload
+
+
+
+#### 10KB Payload
+
+
+
+#### 50KB Payload
+
+
+
+| Metric | 1KB Payload | 10KB Payload | 50KB Payload | 50KB Payload (Reduced Load) |
+| ------------------ | ------------------- | ----------------- | ------------------ | --------------------------- |
+| Concurrent Users | 4_000 | 4_000 | 4_000 | 2_000 |
+| Message Throughput | 28_000 msgs/sec | 28_000 msgs/sec | 28_000 msgs/sec | 14_000 msgs/sec |
+| Median Latency | 13 ms | 16 ms | 27 ms | 19 ms |
+| Latency (p95) | 36 ms | 42 ms | 81 ms | 39 ms |
+| Latency (p99) | 85 ms | 93 ms | 146 ms | 82 ms |
+| Data Received | 31.2 MB/s (10.4 GB) | 268 MB/s (72 GB) | 1284 MB/s (348 GB) | 644 MB/s (176 GB) |
+| Data Sent | 9.2 MB/s (3.1 GB) | 76 MB/s (20.8 GB) | 384 MB/s (104 GB) | 192 MB/s (52 GB) |
+
+> Note: The final column shows results with reduced load (2,000 users) for the 50KB payload test, demonstrating how the system performs with larger payloads under different concurrency levels.
+
+### Large-Scale Broadcasting
+
+This workload demonstrates Realtime's capability to handle high-scale scenarios with a large number of concurrent users and broadcast channels. The test simulates a scenario where each user participates in group communications with periodic message broadcasts:
+
+- Each virtual user (VU):
+ - Establishes and maintains a WebSocket connection (30-120 minutes)
+ - Joins 2 broadcast channels
+ - Sends 1 message per minute to each joined channel
+ - Each message is broadcasted to 100 other users
+
+
+
+| Metric | Value |
+| ------------------- | ------------------ |
+| Concurrent Users | 250_000 |
+| Total Channel Joins | 500_000 |
+| Users per Channel | 100 |
+| Message Throughput | >800_000 msgs/sec |
+| Median Latency | 58 ms |
+| Latency (p95) | 279 ms |
+| Latency (p99) | 508 ms |
+| Data Received | 68 MB/s (600 GB) |
+| Data Sent | 0.64 MB/s (5.7 GB) |
+
+### Realtime Auth
+
+This workload demonstrates Realtime's capability to handle large amounts of new connections per second and channel joins per second with Authentication Row Level Security (RLS) enabled for these channels. The test simulates a scenario where large volumes of users connect to realtime and participate in auth protected communications:
+
+- Each virtual user (VU):
+ - Establishes and maintains a WebSocket connection (2.5 minutes)
+ - Joins 2 broadcast channels
+ - Sends 1 message per minute to each joined channel
+ - Each message is broadcasted to 100 other users
+
+
+
+| Metric | Value |
+| ------------------- | ----------------- |
+| Concurrent Users | 50_000 |
+| Total Channel Joins | 100_000 |
+| Users per Channel | 100 |
+| Message Throughput | >150_000 msgs/sec |
+| New Connection Rate | 500 conn/sec |
+| Channel Join Rate | 1000 joins/sec |
+| Median Latency | 19 ms |
+| Latency (p95) | 49 ms |
+| Latency (p99) | 96 ms |
+
+### Realtime's Postgres Changes
+
+Realtime systems usually require forethought because of their scaling dynamics. For the `Postgres Changes` feature, every change event must be checked to see if the subscribed user has access. For instance, if you have 100 users subscribed to a table where you make a single insert, it will then trigger 100 "reads": one for each user.
+
+There can be a database bottleneck which limits message throughput. If your database cannot authorize the changes rapidly enough, the changes will be delayed until you receive a timeout.
+
+Database changes are processed on a single thread to maintain the change order. That means compute upgrades don't have a large effect on the performance of Postgres change subscriptions. You can estimate the expected maximum throughput for your database below.
+
+If you are using Postgres Changes at scale, you should consider using a separate "public" table without RLS and filters. Alternatively, you can use Realtime server-side only and then re-stream the changes to your clients using a Realtime Broadcast.
+
+Enter your database settings to estimate the maximum throughput for your instance:
+
+
+
+Don't forget to run your own benchmarks to make sure that the performance is acceptable for your use case.
+
+Supabase continues to make improvements to Realtime's Postgres Changes. If you are uncertain about your use case performance, reach out using the [Support Form](https://supabase.com/dashboard/support/new). The support team can advise on the best solution for each use-case.
diff --git a/apps/docs/content/guides/realtime/postgres-changes.mdx b/apps/docs/content/guides/realtime/postgres-changes.mdx
index 51a50672d38..721d29c6d93 100644
--- a/apps/docs/content/guides/realtime/postgres-changes.mdx
+++ b/apps/docs/content/guides/realtime/postgres-changes.mdx
@@ -294,7 +294,7 @@ changes = supabase.channel('schema-db-changes').on_postgres_changes(
The channel name can be any string except 'realtime'.
-### Listening to INSERT events
+### Listening to `INSERT` events
-
If you are using rootless docker, edit `.env` and set `DOCKER_SOCKET_LOCATION` to your docker socket location. For example: `/run/user/1000/docker.sock`. Otherwise, you will see an error like `container supabase-vector exited (0)`.
-
-
-
After all the services have started you can see them running in the background:
```sh
@@ -93,16 +86,13 @@ docker compose ps
All of the services should have a status `running (healthy)`. If you see a status like `created` but not `running`, try starting that service manually with `docker compose start `.
-
Your app is now running with default credentials.
Please [secure your services](#securing-your-services) as soon as possible using the instructions below.
-
-
### Accessing Supabase Studio
You can access Supabase Studio through the API gateway on port `8000`. For example: `http://:8000`, or [localhost:8000](http://localhost:8000) if you are running Docker locally.
@@ -167,7 +157,6 @@ You'll want to update the Studio(Dashboard) frequently to get the latest feature
While we provided you with some example secrets for getting started, you should NEVER deploy your Supabase setup using the defaults we have provided. Please follow all of the steps in this section to ensure you have a secure setup, and then [restart all services](#restarting-all-services) to pick up the changes.
-
### Generate API keys
We need to generate secure keys for accessing your services. We'll use the `JWT Secret` to generate `anon` and `service` API keys using the form below.
@@ -175,7 +164,6 @@ We need to generate secure keys for accessing your services. We'll use the `JWT
2. **Store Securely**: Save the secret in a secure location on your local machine. Don't share this secret publicly or commit it to version control.
3. **Generate a JWT**: Use the form below to generate a new `JWT` using your secret.
-
### Update API keys
@@ -422,8 +410,7 @@ docker rm supabase-analytics
## Demo
-A minimal setup working on Ubuntu, hosted on Digital Ocean.
-
+A minimal setup working on Ubuntu, hosted on DigitalOcean.
-### Demo using Digital Ocean
-1. A Digital Ocean Droplet with 1 GB memory and 25 GB solid-state drive (SSD) is sufficient to start
+### Demo using DigitalOcean
+1. A DigitalOcean Droplet with 1 GB memory and 25 GB solid-state drive (SSD) is sufficient to start
2. To access the Dashboard, use the ipv4 IP address of your Droplet.
3. If you're unable to access Dashboard, run `docker compose ps` to see if the Studio service is running and healthy.
-
-
-
diff --git a/apps/docs/content/guides/storage/debugging/error-codes.mdx b/apps/docs/content/guides/storage/debugging/error-codes.mdx
index 7d76cfe26cb..cce0e9a6878 100644
--- a/apps/docs/content/guides/storage/debugging/error-codes.mdx
+++ b/apps/docs/content/guides/storage/debugging/error-codes.mdx
@@ -6,7 +6,7 @@ subtitle: 'Learn about the Storage error codes and how to resolve them'
sidebar_label: 'Debugging'
---
-## Storage Error Codes
+## Storage error codes
We are transitioning to a new error code system. For backwards compatibility you'll still be able
@@ -60,7 +60,7 @@ Here is the full list of error codes and their descriptions:
| MissingPart | A part of the entity is missing. | 400 | Ensure all parts of the entity are included in the request before completing the operation. |
| SlowDown | The request rate is too high and has been throttled. | 503 | Reduce the request rate or implement exponential backoff and retry mechanisms to handle throttling. |
-## Legacy Error Codes
+## Legacy error codes
As we are transitioning to a new error code system, you might still see the following error format:
diff --git a/apps/docs/content/guides/storage/schema/custom-roles.mdx b/apps/docs/content/guides/storage/schema/custom-roles.mdx
index f020ccbd696..9af072af00e 100644
--- a/apps/docs/content/guides/storage/schema/custom-roles.mdx
+++ b/apps/docs/content/guides/storage/schema/custom-roles.mdx
@@ -10,7 +10,7 @@ In this guide, you will learn how to create and use custom roles with Storage to
Supabase Storage uses the same role-based access control system as any other Supabase service using RLS (Row Level Security).
-## Create a Custom Role
+## Create a custom role
Let's create a custom role `manager` to provide full read access to a specific bucket. For a more advanced setup, see the [RBAC Guide](/docs/guides/auth/custom-claims-and-role-based-access-control-rbac#create-auth-hook-to-apply-user-role).
diff --git a/apps/docs/content/guides/storage/serving/bandwidth.mdx b/apps/docs/content/guides/storage/serving/bandwidth.mdx
index b2153fbb91c..740931c242d 100644
--- a/apps/docs/content/guides/storage/serving/bandwidth.mdx
+++ b/apps/docs/content/guides/storage/serving/bandwidth.mdx
@@ -6,13 +6,13 @@ subtitle: 'Bandwidth & Storage Egress'
sidebar_label: 'Bandwidth & Storage Egress'
---
-## Bandwidth & Storage Egress
+## Bandwidth & Storage egress
Free Plan Organizations in Supabase have a limit of 5 GB of bandwidth. This limit is calculated by the sum of all the data transferred from the Supabase servers to the client. This includes all the data transferred from the database, storage, and functions.
-### Checking Storage Egress Requests in Log Explorer:
+### Checking Storage egress requests in Logs Explorer:
-We have a template query that you can use to get the number of requests for each object in [Log Explorer](/dashboard/project/_/logs/explorer/templates).
+We have a template query that you can use to get the number of requests for each object in [Logs Explorer](/dashboard/project/_/logs/explorer/templates).
```sql
select
@@ -45,7 +45,7 @@ Example of the output:
]
```
-### Calculating Egress:
+### Calculating egress:
If you already know the size of those files, you can calculate the egress by multiplying the number of requests by the size of the file.
You can also get the size of the file with the following cURL:
@@ -67,6 +67,6 @@ Total Egress = 395.76MB
You can see that these values can get quite large, so it's important to keep track of the egress and optimize the files.
-### Optimizing Egress:
+### Optimizing egress:
If you are on the Pro Plan, you can use the [Supabase Image Transformations](/docs/guides/storage/image-transformations) to optimize the images and reduce the egress.
diff --git a/apps/docs/features/docs/MdxBase.tsx b/apps/docs/features/docs/MdxBase.tsx
index 20413a1cc7d..3077c0a59ae 100644
--- a/apps/docs/features/docs/MdxBase.tsx
+++ b/apps/docs/features/docs/MdxBase.tsx
@@ -1,4 +1,4 @@
-import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' }
+import codeHikeTheme from 'config/code-hike.theme.json' with { type: 'json' }
import { remarkCodeHike, type CodeHikeConfig } from '@code-hike/mdx'
import { type SerializeOptions } from 'next-mdx-remote/dist/types'
import { MDXRemote } from 'next-mdx-remote/rsc'
diff --git a/apps/docs/features/docs/Reference.generated.script.ts b/apps/docs/features/docs/Reference.generated.script.ts
index 4eb584ae6a9..42c5f1b6a5c 100644
--- a/apps/docs/features/docs/Reference.generated.script.ts
+++ b/apps/docs/features/docs/Reference.generated.script.ts
@@ -1,27 +1,27 @@
-import { keyBy, isPlainObject } from 'lodash'
+import { isPlainObject, keyBy } from 'lodash'
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import slugify from 'slugify'
import { parse } from 'yaml'
-import { REFERENCES, clientSdkIds } from '~/content/navigation.references'
+import { clientSdkIds, REFERENCES } from '~/content/navigation.references'
import { parseTypeSpec } from '~/features/docs/Reference.typeSpec'
import type { AbbrevApiReferenceSection } from '~/features/docs/Reference.utils'
import { deepFilterRec } from '~/features/helpers.fn'
import type { Json } from '~/features/helpers.types'
-import authSpec from '~/spec/auth_v1_openapi.json' assert { type: 'json' }
-import apiCommonSections from '~/spec/common-api-sections.json' assert { type: 'json' }
-import cliCommonSections from '~/spec/common-cli-sections.json' assert { type: 'json' }
-import commonClientLibSections from '~/spec/common-client-libs-sections.json' assert { type: 'json' }
-import selfHostingAnalyticsCommonSections from '~/spec/common-self-hosting-analytics-sections.json' assert { type: 'json' }
+import authSpec from '~/spec/auth_v1_openapi.json' with { type: 'json' }
+import apiCommonSections from '~/spec/common-api-sections.json' with { type: 'json' }
+import cliCommonSections from '~/spec/common-cli-sections.json' with { type: 'json' }
+import commonClientLibSections from '~/spec/common-client-libs-sections.json' with { type: 'json' }
+import selfHostingAnalyticsCommonSections from '~/spec/common-self-hosting-analytics-sections.json' with { type: 'json' }
import selfHostingAuthCommonSections from '~/spec/common-self-hosting-auth-sections.json'
-import selfHostingFunctionsCommonSections from '~/spec/common-self-hosting-functions-sections.json' assert { type: 'json' }
-import selfHostingRealtimeCommonSections from '~/spec/common-self-hosting-realtime-sections.json' assert { type: 'json' }
-import selfHostingStorageCommonSections from '~/spec/common-self-hosting-storage-sections.json' assert { type: 'json' }
-import storageSpec from '~/spec/storage_v0_openapi.json' assert { type: 'json' }
-import analyticsSpec from '~/spec/transforms/analytics_v0_openapi_deparsed.json' assert { type: 'json' }
-import openApiSpec from '~/spec/transforms/api_v1_openapi_deparsed.json' assert { type: 'json' }
+import selfHostingFunctionsCommonSections from '~/spec/common-self-hosting-functions-sections.json' with { type: 'json' }
+import selfHostingRealtimeCommonSections from '~/spec/common-self-hosting-realtime-sections.json' with { type: 'json' }
+import selfHostingStorageCommonSections from '~/spec/common-self-hosting-storage-sections.json' with { type: 'json' }
+import storageSpec from '~/spec/storage_v0_openapi.json' with { type: 'json' }
+import analyticsSpec from '~/spec/transforms/analytics_v0_openapi_deparsed.json' with { type: 'json' }
+import openApiSpec from '~/spec/transforms/api_v1_openapi_deparsed.json' with { type: 'json' }
import { IApiEndPoint } from './Reference.api.utils'
const DOCS_DIRECTORY = join(dirname(fileURLToPath(import.meta.url)), '../..')
diff --git a/apps/docs/features/docs/Reference.introduction.tsx b/apps/docs/features/docs/Reference.introduction.tsx
index 66e4609c77d..f799668bfe3 100644
--- a/apps/docs/features/docs/Reference.introduction.tsx
+++ b/apps/docs/features/docs/Reference.introduction.tsx
@@ -5,7 +5,7 @@ import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, cn } from
import { getRefMarkdown, MDXRemoteRefs } from '~/features/docs/Reference.mdx'
import { ReferenceSectionWrapper } from '~/features/docs/Reference.ui.client'
-import commonClientLibSections from '~/spec/common-client-libs-sections.json' assert { type: 'json' }
+import commonClientLibSections from '~/spec/common-client-libs-sections.json' with { type: 'json' }
function hasIntro(sections: typeof commonClientLibSections, excludeName?: string) {
return Boolean(
diff --git a/apps/docs/features/docs/Reference.typeSpec.ts b/apps/docs/features/docs/Reference.typeSpec.ts
index fe1a41962d7..589ee7702f7 100644
--- a/apps/docs/features/docs/Reference.typeSpec.ts
+++ b/apps/docs/features/docs/Reference.typeSpec.ts
@@ -6,7 +6,7 @@
* access to a function's type definition, given its name and module.
*/
-import _typeSpec from '~/spec/enrichments/tsdoc_v2/combined.json' assert { type: 'json' }
+import _typeSpec from '~/spec/enrichments/tsdoc_v2/combined.json' with { type: 'json' }
// [Charis] 2024-07-10
// Types are more trouble than they're worth here: manually defining the types
@@ -303,7 +303,11 @@ function parseMethod(
function parseSignature(
signature: any,
map: Map
-): { params: Array; ret: ReturnType; comment?: Comment } {
+): {
+ params: Array
+ ret: ReturnType
+ comment?: Comment
+} {
const params: Array = (signature.parameters ?? []).map((param: any) => {
const type = parseType(param.type, map)
diff --git a/apps/docs/lib/docs.ts b/apps/docs/lib/docs.ts
index 998752e2016..4be5a7dfb01 100644
--- a/apps/docs/lib/docs.ts
+++ b/apps/docs/lib/docs.ts
@@ -4,12 +4,12 @@ import { serialize } from 'next-mdx-remote/serialize'
import type { SerializeOptions } from 'next-mdx-remote/dist/types'
import { existsSync } from 'node:fs'
import { readdir, readFile } from 'node:fs/promises'
-import { join, extname, sep, basename } from 'node:path'
+import { basename, extname, join, sep } from 'node:path'
import remarkGfm from 'remark-gfm'
import rehypeKatex from 'rehype-katex'
import remarkMath from 'remark-math'
-import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' }
+import codeHikeTheme from 'config/code-hike.theme.json' with { type: 'json' }
// MUST be process.cwd() here, not import.meta.url, or files that are added
// with outputFileTracingIncludes (not auto-traced) will not be found at
diff --git a/apps/docs/lib/mdx/generateRefMarkdown.tsx b/apps/docs/lib/mdx/generateRefMarkdown.tsx
index 165783822ba..1cd3896d1ac 100644
--- a/apps/docs/lib/mdx/generateRefMarkdown.tsx
+++ b/apps/docs/lib/mdx/generateRefMarkdown.tsx
@@ -1,7 +1,7 @@
import fs from 'fs'
import { CodeHikeConfig, remarkCodeHike } from '@code-hike/mdx'
-import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' }
+import codeHikeTheme from 'config/code-hike.theme.json' with { type: 'json' }
import matter from 'gray-matter'
import { serialize } from 'next-mdx-remote/serialize'
import remarkGfm from 'remark-gfm'
diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs
index 37333dad42d..167677a302d 100644
--- a/apps/docs/next.config.mjs
+++ b/apps/docs/next.config.mjs
@@ -8,7 +8,7 @@ import remarkGfm from 'remark-gfm'
import configureBundleAnalyzer from '@next/bundle-analyzer'
import withYaml from 'next-plugin-yaml'
-import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' }
+import codeHikeTheme from 'config/code-hike.theme.json' with { type: 'json' }
import remotePatterns from './lib/remotePatterns.js'
const withBundleAnalyzer = configureBundleAnalyzer({
diff --git a/apps/docs/public/humans.txt b/apps/docs/public/humans.txt
index b631dfe115c..73b70492351 100644
--- a/apps/docs/public/humans.txt
+++ b/apps/docs/public/humans.txt
@@ -56,6 +56,7 @@ Kevin Brolly
Kevin Grüneberg
Lakshan Perera
Laura C
+Laurence Isla
Long Hoang
Łukasz Niemier
Margarita Sandomirskaia
diff --git a/apps/docs/public/img/guides/auth-workos/supabase-project-settings-url.png b/apps/docs/public/img/guides/auth-workos/supabase-project-settings-url.png
new file mode 100644
index 00000000000..ed1312ac170
Binary files /dev/null and b/apps/docs/public/img/guides/auth-workos/supabase-project-settings-url.png differ
diff --git a/apps/docs/public/img/guides/auth-workos/supabase-workos-configuration.png b/apps/docs/public/img/guides/auth-workos/supabase-workos-configuration.png
new file mode 100644
index 00000000000..a2fb6b25061
Binary files /dev/null and b/apps/docs/public/img/guides/auth-workos/supabase-workos-configuration.png differ
diff --git a/apps/docs/public/img/guides/auth-workos/workos-auth-config-dashboard.png b/apps/docs/public/img/guides/auth-workos/workos-auth-config-dashboard.png
new file mode 100644
index 00000000000..814f4d94769
Binary files /dev/null and b/apps/docs/public/img/guides/auth-workos/workos-auth-config-dashboard.png differ
diff --git a/apps/docs/public/img/guides/auth-workos/workos-clientid-redirect-uri.png b/apps/docs/public/img/guides/auth-workos/workos-clientid-redirect-uri.png
deleted file mode 100644
index 131d0471042..00000000000
Binary files a/apps/docs/public/img/guides/auth-workos/workos-clientid-redirect-uri.png and /dev/null differ
diff --git a/apps/docs/public/img/guides/auth-workos/workos-create-organization.png b/apps/docs/public/img/guides/auth-workos/workos-create-organization.png
index 4f9d7798de5..f7b6dedc3ce 100644
Binary files a/apps/docs/public/img/guides/auth-workos/workos-create-organization.png and b/apps/docs/public/img/guides/auth-workos/workos-create-organization.png differ
diff --git a/apps/docs/public/img/guides/auth-workos/workos-dashboard-get-client-id-and-key.png b/apps/docs/public/img/guides/auth-workos/workos-dashboard-get-client-id-and-key.png
new file mode 100644
index 00000000000..dc7e42a8b96
Binary files /dev/null and b/apps/docs/public/img/guides/auth-workos/workos-dashboard-get-client-id-and-key.png differ
diff --git a/apps/docs/public/img/guides/auth-workos/workos-secret-key.png b/apps/docs/public/img/guides/auth-workos/workos-secret-key.png
deleted file mode 100644
index 9c2df99be53..00000000000
Binary files a/apps/docs/public/img/guides/auth-workos/workos-secret-key.png and /dev/null differ
diff --git a/apps/docs/public/img/guides/auth-workos/workos-set-supabase-redirect.png b/apps/docs/public/img/guides/auth-workos/workos-set-supabase-redirect.png
new file mode 100644
index 00000000000..0fbb94cc261
Binary files /dev/null and b/apps/docs/public/img/guides/auth-workos/workos-set-supabase-redirect.png differ
diff --git a/apps/docs/public/img/guides/auth-workos/workos-setup-identity-provider.png b/apps/docs/public/img/guides/auth-workos/workos-setup-identity-provider.png
deleted file mode 100644
index de464f443c2..00000000000
Binary files a/apps/docs/public/img/guides/auth-workos/workos-setup-identity-provider.png and /dev/null differ
diff --git a/apps/docs/public/img/guides/realtime/broadcast-auth.png b/apps/docs/public/img/guides/realtime/broadcast-auth.png
new file mode 100644
index 00000000000..74a6cbc1a36
Binary files /dev/null and b/apps/docs/public/img/guides/realtime/broadcast-auth.png differ
diff --git a/apps/docs/public/img/guides/realtime/broadcast-large.png b/apps/docs/public/img/guides/realtime/broadcast-large.png
new file mode 100644
index 00000000000..9b881ca7036
Binary files /dev/null and b/apps/docs/public/img/guides/realtime/broadcast-large.png differ
diff --git a/apps/docs/public/img/guides/realtime/broadcast-performance.png b/apps/docs/public/img/guides/realtime/broadcast-performance.png
new file mode 100644
index 00000000000..24177d7cbc1
Binary files /dev/null and b/apps/docs/public/img/guides/realtime/broadcast-performance.png differ
diff --git a/apps/docs/public/img/guides/realtime/payload-size-10kb.png b/apps/docs/public/img/guides/realtime/payload-size-10kb.png
new file mode 100644
index 00000000000..bda28c7a90e
Binary files /dev/null and b/apps/docs/public/img/guides/realtime/payload-size-10kb.png differ
diff --git a/apps/docs/public/img/guides/realtime/payload-size-1kb.png b/apps/docs/public/img/guides/realtime/payload-size-1kb.png
new file mode 100644
index 00000000000..b7492a489a6
Binary files /dev/null and b/apps/docs/public/img/guides/realtime/payload-size-1kb.png differ
diff --git a/apps/docs/public/img/guides/realtime/payload-size-50kb-small.png b/apps/docs/public/img/guides/realtime/payload-size-50kb-small.png
new file mode 100644
index 00000000000..b9e562b927e
Binary files /dev/null and b/apps/docs/public/img/guides/realtime/payload-size-50kb-small.png differ
diff --git a/apps/docs/spec/api_v1_openapi.json b/apps/docs/spec/api_v1_openapi.json
index 1660b7e6d45..3802f4ea3f4 100644
--- a/apps/docs/spec/api_v1_openapi.json
+++ b/apps/docs/spec/api_v1_openapi.json
@@ -88,6 +88,35 @@
"security": [{ "bearer": [] }]
}
},
+ "/v1/branches/{branch_id}/push": {
+ "post": {
+ "operationId": "v1-push-a-branch",
+ "summary": "Pushes a database branch",
+ "description": "Pushes the specified database branch",
+ "parameters": [
+ {
+ "name": "branch_id",
+ "required": true,
+ "in": "path",
+ "description": "Branch ID",
+ "schema": { "type": "string" }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/BranchUpdateResponse" }
+ }
+ }
+ },
+ "500": { "description": "Failed to push database branch" }
+ },
+ "tags": ["Environments"],
+ "security": [{ "bearer": [] }]
+ }
+ },
"/v1/branches/{branch_id}/reset": {
"post": {
"operationId": "v1-reset-a-branch",
@@ -107,7 +136,7 @@
"description": "",
"content": {
"application/json": {
- "schema": { "$ref": "#/components/schemas/BranchResetResponse" }
+ "schema": { "$ref": "#/components/schemas/BranchUpdateResponse" }
}
}
},
@@ -284,6 +313,24 @@
"security": [{ "oauth2": ["write"] }]
}
},
+ "/v1/oauth/revoke": {
+ "post": {
+ "operationId": "v1-revoke-token",
+ "summary": "[Beta] Revoke oauth app authorization and it's corresponding tokens",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": { "$ref": "#/components/schemas/OAuthRevokeTokenBodyDto" }
+ }
+ }
+ },
+ "responses": { "204": { "description": "" } },
+ "tags": ["OAuth"],
+ "security": [{ "oauth2": ["write"] }]
+ }
+ },
"/v1/snippets": {
"get": {
"operationId": "v1-list-all-snippets",
@@ -1977,6 +2024,24 @@
"security": [{ "bearer": [] }]
}
},
+ "/v1/projects/{ref}/pause": {
+ "post": {
+ "operationId": "v1-pause-a-project",
+ "summary": "Pauses the given project",
+ "parameters": [
+ {
+ "name": "ref",
+ "required": true,
+ "in": "path",
+ "description": "Project ref",
+ "schema": { "minLength": 20, "maxLength": 20, "type": "string" }
+ }
+ ],
+ "responses": { "200": { "description": "" }, "403": { "description": "" } },
+ "tags": ["Projects"],
+ "security": [{ "bearer": [] }]
+ }
+ },
"/v1/projects/{ref}/database/query": {
"post": {
"operationId": "v1-run-a-query",
@@ -2670,9 +2735,13 @@
"UpdateBranchBody": {
"type": "object",
"properties": {
+ "reset_on_push": {
+ "type": "boolean",
+ "deprecated": true,
+ "description": "This field is deprecated and will be ignored. Use v1-reset-a-branch endpoint directly instead."
+ },
"branch_name": { "type": "string" },
"git_branch": { "type": "string" },
- "reset_on_push": { "type": "boolean" },
"persistent": { "type": "boolean" },
"status": {
"enum": [
@@ -2691,14 +2760,17 @@
"type": "object",
"properties": {
"pr_number": { "type": "integer", "format": "int32" },
- "latest_check_run_id": { "type": "integer", "format": "int64" },
+ "latest_check_run_id": {
+ "type": "number",
+ "deprecated": true,
+ "description": "This field is deprecated and will not be populated."
+ },
"id": { "type": "string" },
"name": { "type": "string" },
"project_ref": { "type": "string" },
"parent_project_ref": { "type": "string" },
"is_default": { "type": "boolean" },
"git_branch": { "type": "string" },
- "reset_on_push": { "type": "boolean" },
"persistent": { "type": "boolean" },
"status": {
"enum": [
@@ -2720,7 +2792,6 @@
"project_ref",
"parent_project_ref",
"is_default",
- "reset_on_push",
"persistent",
"status",
"created_at",
@@ -2732,7 +2803,7 @@
"properties": { "message": { "type": "string" } },
"required": ["message"]
},
- "BranchResetResponse": {
+ "BranchUpdateResponse": {
"type": "object",
"properties": { "workflow_run_id": { "type": "string" }, "message": { "type": "string" } },
"required": ["workflow_run_id", "message"]
@@ -2791,10 +2862,7 @@
"type": "object",
"properties": {
"db_pass": { "type": "string", "description": "Database password" },
- "name": {
- "type": "string",
- "description": "Name of your project, should not contain dots"
- },
+ "name": { "type": "string", "description": "Name of your project" },
"organization_id": { "type": "string", "description": "Slug of your organization" },
"plan": {
"type": "string",
@@ -2939,6 +3007,16 @@
},
"required": ["expires_in", "token_type", "access_token", "refresh_token"]
},
+ "OAuthRevokeTokenBodyDto": {
+ "type": "object",
+ "properties": {
+ "client_id": { "type": "string", "format": "uuid" },
+ "client_secret": { "type": "string" },
+ "refresh_token": { "type": "string" }
+ },
+ "required": ["client_id", "client_secret", "refresh_token"],
+ "additionalProperties": false
+ },
"SnippetProject": {
"type": "object",
"properties": {
diff --git a/apps/docs/spec/common-api-sections.json b/apps/docs/spec/common-api-sections.json
index acbc5d0da6a..821e282f141 100644
--- a/apps/docs/spec/common-api-sections.json
+++ b/apps/docs/spec/common-api-sections.json
@@ -297,6 +297,12 @@
"slug": "v1-list-all-branches",
"type": "operation"
},
+ {
+ "id": "v1-push-a-branch",
+ "title": "Push a branch",
+ "slug": "v1-push-a-branch",
+ "type": "operation"
+ },
{
"id": "v1-reset-a-branch",
"title": "Reset a branch",
@@ -326,6 +332,12 @@
"title": "Exchange oauth token",
"slug": "v1-exchange-oauth-token",
"type": "operation"
+ },
+ {
+ "id": "v1-revoke-token",
+ "title": "Revoke token",
+ "slug": "v1-revoke-token",
+ "type": "operation"
}
]
},
@@ -423,6 +435,12 @@
"slug": "v1-list-all-projects",
"type": "operation"
},
+ {
+ "id": "v1-pause-a-project",
+ "title": "Pause a project",
+ "slug": "v1-pause-a-project",
+ "type": "operation"
+ },
{
"id": "v1-update-network-restrictions",
"title": "Update network restrictions",
diff --git a/apps/docs/spec/transforms/api_v1_openapi_deparsed.json b/apps/docs/spec/transforms/api_v1_openapi_deparsed.json
index 6c6e1572af7..f6305737fb3 100644
--- a/apps/docs/spec/transforms/api_v1_openapi_deparsed.json
+++ b/apps/docs/spec/transforms/api_v1_openapi_deparsed.json
@@ -172,15 +172,17 @@
"schema": {
"type": "object",
"properties": {
+ "reset_on_push": {
+ "type": "boolean",
+ "deprecated": true,
+ "description": "This field is deprecated and will be ignored. Use v1-reset-a-branch endpoint directly instead."
+ },
"branch_name": {
"type": "string"
},
"git_branch": {
"type": "string"
},
- "reset_on_push": {
- "type": "boolean"
- },
"persistent": {
"type": "boolean"
},
@@ -213,8 +215,9 @@
"format": "int32"
},
"latest_check_run_id": {
- "type": "integer",
- "format": "int64"
+ "type": "number",
+ "deprecated": true,
+ "description": "This field is deprecated and will not be populated."
},
"id": {
"type": "string"
@@ -234,9 +237,6 @@
"git_branch": {
"type": "string"
},
- "reset_on_push": {
- "type": "boolean"
- },
"persistent": {
"type": "boolean"
},
@@ -264,7 +264,6 @@
"project_ref",
"parent_project_ref",
"is_default",
- "reset_on_push",
"persistent",
"status",
"created_at",
@@ -329,6 +328,54 @@
]
}
},
+ "/v1/branches/{branch_id}/push": {
+ "post": {
+ "operationId": "v1-push-a-branch",
+ "summary": "Pushes a database branch",
+ "description": "Pushes the specified database branch",
+ "parameters": [
+ {
+ "name": "branch_id",
+ "required": true,
+ "in": "path",
+ "description": "Branch ID",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "workflow_run_id": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ }
+ },
+ "required": ["workflow_run_id", "message"]
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Failed to push database branch"
+ }
+ },
+ "tags": ["Environments"],
+ "security": [
+ {
+ "bearer": []
+ }
+ ]
+ }
+ },
"/v1/branches/{branch_id}/reset": {
"post": {
"operationId": "v1-reset-a-branch",
@@ -497,7 +544,7 @@
},
"name": {
"type": "string",
- "description": "Name of your project, should not contain dots"
+ "description": "Name of your project"
},
"organization_id": {
"type": "string",
@@ -896,6 +943,48 @@
]
}
},
+ "/v1/oauth/revoke": {
+ "post": {
+ "operationId": "v1-revoke-token",
+ "summary": "[Beta] Revoke oauth app authorization and it's corresponding tokens",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "client_id": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "client_secret": {
+ "type": "string"
+ },
+ "refresh_token": {
+ "type": "string"
+ }
+ },
+ "required": ["client_id", "client_secret", "refresh_token"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": ""
+ }
+ },
+ "tags": ["OAuth"],
+ "security": [
+ {
+ "oauth2": ["write"]
+ }
+ ]
+ }
+ },
"/v1/snippets": {
"get": {
"operationId": "v1-list-all-snippets",
@@ -1753,8 +1842,9 @@
"format": "int32"
},
"latest_check_run_id": {
- "type": "integer",
- "format": "int64"
+ "type": "number",
+ "deprecated": true,
+ "description": "This field is deprecated and will not be populated."
},
"id": {
"type": "string"
@@ -1774,9 +1864,6 @@
"git_branch": {
"type": "string"
},
- "reset_on_push": {
- "type": "boolean"
- },
"persistent": {
"type": "boolean"
},
@@ -1804,7 +1891,6 @@
"project_ref",
"parent_project_ref",
"is_default",
- "reset_on_push",
"persistent",
"status",
"created_at",
@@ -1905,8 +1991,9 @@
"format": "int32"
},
"latest_check_run_id": {
- "type": "integer",
- "format": "int64"
+ "type": "number",
+ "deprecated": true,
+ "description": "This field is deprecated and will not be populated."
},
"id": {
"type": "string"
@@ -1926,9 +2013,6 @@
"git_branch": {
"type": "string"
},
- "reset_on_push": {
- "type": "boolean"
- },
"persistent": {
"type": "boolean"
},
@@ -1956,7 +2040,6 @@
"project_ref",
"parent_project_ref",
"is_default",
- "reset_on_push",
"persistent",
"status",
"created_at",
@@ -8021,6 +8104,39 @@
]
}
},
+ "/v1/projects/{ref}/pause": {
+ "post": {
+ "operationId": "v1-pause-a-project",
+ "summary": "Pauses the given project",
+ "parameters": [
+ {
+ "name": "ref",
+ "required": true,
+ "in": "path",
+ "description": "Project ref",
+ "schema": {
+ "minLength": 20,
+ "maxLength": 20,
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": ""
+ },
+ "403": {
+ "description": ""
+ }
+ },
+ "tags": ["Projects"],
+ "security": [
+ {
+ "bearer": []
+ }
+ ]
+ }
+ },
"/v1/projects/{ref}/database/query": {
"post": {
"operationId": "v1-run-a-query",
@@ -10072,15 +10188,17 @@
"UpdateBranchBody": {
"type": "object",
"properties": {
+ "reset_on_push": {
+ "type": "boolean",
+ "deprecated": true,
+ "description": "This field is deprecated and will be ignored. Use v1-reset-a-branch endpoint directly instead."
+ },
"branch_name": {
"type": "string"
},
"git_branch": {
"type": "string"
},
- "reset_on_push": {
- "type": "boolean"
- },
"persistent": {
"type": "boolean"
},
@@ -10105,8 +10223,9 @@
"format": "int32"
},
"latest_check_run_id": {
- "type": "integer",
- "format": "int64"
+ "type": "number",
+ "deprecated": true,
+ "description": "This field is deprecated and will not be populated."
},
"id": {
"type": "string"
@@ -10126,9 +10245,6 @@
"git_branch": {
"type": "string"
},
- "reset_on_push": {
- "type": "boolean"
- },
"persistent": {
"type": "boolean"
},
@@ -10156,7 +10272,6 @@
"project_ref",
"parent_project_ref",
"is_default",
- "reset_on_push",
"persistent",
"status",
"created_at",
@@ -10172,7 +10287,7 @@
},
"required": ["message"]
},
- "BranchResetResponse": {
+ "BranchUpdateResponse": {
"type": "object",
"properties": {
"workflow_run_id": {
@@ -10285,7 +10400,7 @@
},
"name": {
"type": "string",
- "description": "Name of your project, should not contain dots"
+ "description": "Name of your project"
},
"organization_id": {
"type": "string",
@@ -10479,6 +10594,23 @@
},
"required": ["expires_in", "token_type", "access_token", "refresh_token"]
},
+ "OAuthRevokeTokenBodyDto": {
+ "type": "object",
+ "properties": {
+ "client_id": {
+ "type": "string",
+ "format": "uuid"
+ },
+ "client_secret": {
+ "type": "string"
+ },
+ "refresh_token": {
+ "type": "string"
+ }
+ },
+ "required": ["client_id", "client_secret", "refresh_token"],
+ "additionalProperties": false
+ },
"SnippetProject": {
"type": "object",
"properties": {
diff --git a/apps/studio/.storybook/main.js b/apps/studio/.storybook/main.js
deleted file mode 100644
index bc8160546ae..00000000000
--- a/apps/studio/.storybook/main.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const path = require('path')
-module.exports = {
- stories: ['./*.stories.mdx', '../components/**/*.stories.@(js|jsx|ts|tsx)'],
- addons: [
- '@storybook/addon-links',
- '@storybook/addon-essentials',
- '@storybook/addon-interactions',
- 'storybook-dark-mode',
- ],
-
- webpackFinal: async (config) => {
- config.resolve.modules = [...(config.resolve.modules || []), path.resolve(__dirname, '../')]
- return config
- },
-}
diff --git a/apps/studio/.storybook/preview.css b/apps/studio/.storybook/preview.css
deleted file mode 100644
index 29b55284e98..00000000000
--- a/apps/studio/.storybook/preview.css
+++ /dev/null
@@ -1,113 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-.dark,
-.light,
-.light .docs-story,
-.dark .docs-story {
- @apply bg-studio;
-}
-
-/* // date picker */
-/* !!!! THIS IS A COPY OF THE styles/date-picker.scss !! */
-
-.react-datepicker__input-container input {
- @apply block w-full text-base md:text-sm bg-white border border-muted rounded shadow-sm;
-}
-
-.react-datepicker-popper {
- @apply z-40 w-72 text-sm bg-surface-100 shadow px-3 py-2 border-2 border-background rounded;
-}
-
-.react-datepicker-left {
- @apply absolute left-0 right-auto top-11 transform-none !important;
-}
-
-.react-datepicker-right {
- @apply absolute right-0 left-auto top-11 transform-none !important;
-}
-
-.react-datepicker__portal {
- @apply absolute z-10 w-72 text-sm transform-none bg-white shadow px-3 py-2 top-12 right-0 border-2 border-background rounded;
-}
-
-.react-datepicker__month-container {
- @apply flex flex-col;
-}
-
-.react-datepicker__month {
- @apply flex flex-col;
- @apply -space-y-px;
-}
-
-.react-datepicker__current-month {
- @apply ml-2.5 text-lg font-semibold text-border-stronger;
-}
-
-.react-datepicker__week {
- @apply flex -space-x-px;
-}
-
-.react-datepicker__day-names {
- @apply flex -space-x-px text-foreground-lighter font-normal text-center text-xs;
-}
-
-.react-datepicker__day-name {
- @apply w-10 h-10 flex items-center justify-center py-1 rounded-full;
-}
-
-.react-datepicker__navigation {
- @apply absolute top-2;
-}
-
-.react-datepicker__navigation--previous {
- @apply right-12 w-10 h-10 rounded transition flex items-center justify-center hover:bg-studio;
-}
-
-.react-datepicker__navigation--next {
- @apply right-4 w-10 h-10 rounded transition flex items-center justify-center hover:bg-studio;
-}
-
-.react-datepicker__day {
- @apply w-10 h-10 flex items-center font-normal justify-center text-sm leading-loose transition text-foreground-light;
- /* @apply mb-1 py-1; */
- @apply -space-y-px;
- @apply border border-default;
-}
-
-.react-datepicker__day--disabled {
- @apply cursor-not-allowed opacity-40 hover:bg-transparent;
-}
-
-.react-datepicker__day--outside-month {
- @apply text-border-stronger;
-}
-
-.react-datepicker__day--in-range {
- @apply bg-brand-300 text-scale-fixed-100 border-brand-300;
-}
-
-.react-datepicker__day--in-selecting-range {
- @apply bg-brand-400 text-scale-fixed-100 border-brand-400;
-}
-
-.react-datepicker__day--selecting-range-start {
- @apply bg-studio;
-}
-
-.react-datepicker__day--selecting-range-end {
- @apply bg-studio;
-}
-
-.react-datepicker__day--selected {
- @apply bg-brand-300 text-white;
-}
-
-.react-datepicker__day--range-start {
- @apply bg-brand text-white hover:text-border-strong hover:bg-white;
-}
-
-.react-datepicker__day--range-end {
- @apply bg-brand text-white hover:text-border-strong hover:bg-white;
-}
diff --git a/apps/studio/.storybook/preview.js b/apps/studio/.storybook/preview.js
deleted file mode 100644
index b91e38238f4..00000000000
--- a/apps/studio/.storybook/preview.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import './preview.css'
-
-export const parameters = {
- actions: { argTypesRegex: '^on[A-Z].*' },
- controls: {
- matchers: {
- color: /(background|color)$/i,
- date: /Date$/,
- },
- },
- darkMode: {
- darkClass: 'dark',
- lightClass: 'light',
- stylePreview: true,
- },
-}
-
-export const decorators = [
- (Story) => {
- return
- },
-]
diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx
index c04cdd98f66..f6423222942 100644
--- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx
+++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx
@@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
import { useFlag } from 'hooks/ui/useFlag'
-import { TELEMETRY_EVENTS } from 'lib/constants/telemetry'
+import { TelemetryActions } from 'lib/constants/telemetry'
import { useAppStateSnapshot } from 'state/app-state'
import { Badge, Button, Modal, ScrollArea, cn } from 'ui'
import { FEATURE_PREVIEWS, useFeaturePreviewContext } from './FeaturePreviewContext'
@@ -37,9 +37,10 @@ const FeaturePreviewModal = () => {
const toggleFeature = () => {
onUpdateFlag(selectedFeatureKey, !isSelectedFeatureEnabled)
sendEvent({
- action: TELEMETRY_EVENTS.FEATURE_PREVIEWS,
- label: selectedFeatureKey,
- value: isSelectedFeatureEnabled ? 'disabled' : 'enabled',
+ action: isSelectedFeatureEnabled
+ ? TelemetryActions.FEATURE_PREVIEW_DISABLED
+ : TelemetryActions.FEATURE_PREVIEW_ENABLED,
+ properties: { feature: selectedFeatureKey },
})
}
diff --git a/apps/studio/components/interfaces/Auth/EmailRateLimitsAlert/EmailRateLimitsAlert.tsx b/apps/studio/components/interfaces/Auth/EmailRateLimitsAlert/EmailRateLimitsAlert.tsx
index 843ce6f9e74..4eb4b01e371 100644
--- a/apps/studio/components/interfaces/Auth/EmailRateLimitsAlert/EmailRateLimitsAlert.tsx
+++ b/apps/studio/components/interfaces/Auth/EmailRateLimitsAlert/EmailRateLimitsAlert.tsx
@@ -1,11 +1,16 @@
import Link from 'next/link'
import { useParams } from 'common'
-import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, WarningIcon } from 'ui'
+import {
+ AlertDescription_Shadcn_,
+ AlertTitle_Shadcn_,
+ Alert_Shadcn_,
+ Button,
+ WarningIcon,
+} from 'ui'
export function EmailRateLimitsAlert() {
- const { ref: projectRef } = useParams()
- const after20240926 = Date.now() >= new Date('20240926T00:00:00Z').getTime()
+ const { ref } = useParams()
return (
@@ -14,30 +19,21 @@ export function EmailRateLimitsAlert() {
You're using the built-in email service. The service has rate limits and it's not meant to
be used for production apps. Check the{' '}
+ {/* [Refactor] Swap for InlineLink component once https://github.com/supabase/supabase/pull/30494 is in */}
documentation
{' '}
- for an up-to-date information on the current rate limits.{' '}
-
- Set up a custom SMTP server now.
-
-
-
- {after20240926
- ? 'To fight abuse, Auth email messages are restricted '
- : 'On 26th September: To fight abuse, Auth email messages will be restricted '}
- to your project's organization members. For example, if your organization has 3 members with
- addresses: person-a@example.com, person-b@example.com and{' '}
- person-c@example.com, messages will be{' '}
- sent to those addresses only. Set up custom SMTP to send to any user.
+ for an up-to-date information on the current rate limits.
+
)
diff --git a/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.tsx b/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.tsx
index 9bced7ff316..80d6ba89f5d 100644
--- a/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.tsx
+++ b/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.tsx
@@ -5,7 +5,7 @@ import { FormHeader } from 'components/ui/Forms/FormHeader'
import { FormPanel } from 'components/ui/Forms/FormPanel'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
-import { Tabs, Tabs_Shadcn_, TabsContent_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_ } from 'ui'
+import { Tabs_Shadcn_, TabsContent_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_ } from 'ui'
import { TEMPLATES_SCHEMAS } from '../AuthTemplatesValidation'
import EmailRateLimitsAlert from '../EmailRateLimitsAlert'
import TemplateEditor from './TemplateEditor'
@@ -39,7 +39,11 @@ const EmailTemplates = () => {
{isError && (
)}
- {isLoading && }
+ {isLoading && (
+
+ By enabling this, you grant permission for our support team to access your
+ project temporarily and, if applicable, to use AI tools to assist in
+ diagnosing and resolving issues. This access may involve analyzing
+ database configurations, query performance, and other relevant data to
+ expedite troubleshooting and enhance support accuracy. We are committed to
+ maintaining strict data privacy and security standards in all support
+ activities.{' '}
+
+ Privacy Policy
+
+