+
+
+ Generate GPT text completions using OpenAI in Edge Functions.
+
+
+
+
+
+
+ Use Supabase as a Retrieval Store for your ChatGPT plugin.
+
+
+
+
+
+
+ Learn how to build a ChatGPT-style doc search powered by Next.js, OpenAI, and Supabase.
+
+
+
{/* */}
@@ -49,13 +106,45 @@ Check out all of the AI [templates and examples](https://github.com/supabase/sup
{/* */}
- {aiIntegrations.map((x) => (
-
-
- {x.description}
-
-
- ))}
+
+
+
+ OpenAI is an AI research and deployment company. Supabase provides a simple way to use
+ OpenAI in your applications.
+
+
+
+
+
+
+ A fully managed service that offers a choice of high-performing foundation models from
+ leading AI companies.
+
+
+
+
+
+
+ Hugging Face is an open-source provider of NLP technologies. Supabase provides a simple way
+ to use Hugging Face's models in your applications.
+
+
+
+
+
+
+ LangChain is a language-agnostic, open-source, and self-hosted API for text translation,
+ summarization, and sentiment analysis.
+
+
+
+
+
+
+ LlamaIndex is a data framework for your LLM applications.
+
+
+
{/* */}
@@ -65,32 +154,31 @@ Check out all of the AI [templates and examples](https://github.com/supabase/sup
{/* */}
- {[
- {
- name: 'Berri AI Boosts Productivity by Migrating from AWS RDS to Supabase with pgvector',
- description:
- 'Learn how Berri AI overcame challenges with self-hosting their vector database on AWS RDS and successfully migrated to Supabase.',
- href: 'https://supabase.com/customers/berriai',
- },
- {
- name: 'Firecrawl switches from Pinecone to Supabase for Postgres vector embeddings',
- description:
- 'How Firecrawl boosts efficiency and accuracy of chat powered search for documentation using Supabase with pgvector',
- href: 'https://supabase.com/customers/firecrawl',
- },
- {
- name: 'Markprompt: GDPR-Compliant AI Chatbots for Docs and Websites',
- description:
- "AI-powered chatbot platform, Markprompt, empowers developers to deliver efficient and GDPR-compliant prompt experiences on top of their content, by leveraging Supabase's secure and privacy-focused database and authentication solutions",
- href: 'https://supabase.com/customers/markprompt',
- },
- ].map((x) => (
-
-
- {x.description}
-
-
- ))}
+
+
+
+ Learn how Berri AI overcame challenges with self-hosting their vector database on AWS RDS
+ and successfully migrated to Supabase.
+
+
+
+
+
+
+ How Firecrawl boosts efficiency and accuracy of chat powered search for documentation using
+ Supabase with pgvector
+
+
+
+
+
+
+ AI-powered chatbot platform, Markprompt, empowers developers to deliver efficient and
+ GDPR-compliant prompt experiences on top of their content, by leveraging Supabase's secure
+ and privacy-focused database and authentication solutions
+
+
+
{/* */}
diff --git a/apps/docs/content/guides/auth/auth-hooks.mdx b/apps/docs/content/guides/auth/auth-hooks.mdx
index 94471ff88032e..bc0a4d34ede33 100644
--- a/apps/docs/content/guides/auth/auth-hooks.mdx
+++ b/apps/docs/content/guides/auth/auth-hooks.mdx
@@ -366,37 +366,39 @@ Outside of runtime errors, both HTTP Hooks and Postgres Hooks return timeout err
Each Hook description contains an example JSON Schema which you can use in conjunction with [JSON Schema Faker](https://json-schema-faker.js.org/) in order to generate a mock payload. For HTTP Hooks, you can also use [the Standard Webhooks Testing Tool](https://www.standardwebhooks.com/simulate) to simulate a request.
+
+
+ Customize the access token issued by Supabase Auth
+
+
+
+
+
+
+ Use a custom SMS provider to send authentication messages
+
+
+
+
+
+
+ Use a custom email provider to send authentication messages
+
+
+
+
+
+
+ Add additional checks to the MFA verification flow
+
+
+
+
+
+
+ Add additional checks to the password verification flow
+
+
+
diff --git a/apps/docs/content/guides/auth/oauth-server.mdx b/apps/docs/content/guides/auth/oauth-server.mdx
index f6b5c9736cee8..31df7fae5fced 100644
--- a/apps/docs/content/guides/auth/oauth-server.mdx
+++ b/apps/docs/content/guides/auth/oauth-server.mdx
@@ -54,35 +54,34 @@ OAuth 2.1 Server works seamlessly with your existing Supabase Auth configuration
To enable OAuth 2.1 Server in your project, follow these guides:
- {[
- {
- name: 'Getting Started',
- description:
- 'Enable OAuth 2.1, configure your authorization endpoint, and register your first client.',
- href: '/guides/auth/oauth-server/getting-started',
- },
- {
- name: 'OAuth Flows',
- description: 'Detailed walkthrough of authorization code and refresh token flows.',
- href: '/guides/auth/oauth-server/oauth-flows',
- },
- {
- name: 'MCP Authentication',
- description: 'Authenticate AI agents and LLM tools using Model Context Protocol.',
- href: '/guides/auth/oauth-server/mcp-authentication',
- },
- {
- name: 'Token Security & RLS',
- description: 'Control data access with Row Level Security policies for OAuth clients.',
- href: '/guides/auth/oauth-server/token-security',
- },
- ].map((x) => (
-
-
- {x.description}
-
-
- ))}
+
+
+
+ Enable OAuth 2.1, configure your authorization endpoint, and register your first client.
+
+
+
+
+
+
+ Detailed walkthrough of authorization code and refresh token flows.
+
+
+
+
+
+
+ Authenticate AI agents and LLM tools using Model Context Protocol.
+
+
+
+
+
+
+ Control data access with Row Level Security policies for OAuth clients.
+
+
+
## Resources
diff --git a/apps/docs/content/guides/auth/server-side.mdx b/apps/docs/content/guides/auth/server-side.mdx
index d0fdc6cd10828..782db4bc501e6 100644
--- a/apps/docs/content/guides/auth/server-side.mdx
+++ b/apps/docs/content/guides/auth/server-side.mdx
@@ -20,28 +20,16 @@ We have developed an [`@supabase/ssr`](https://www.npmjs.com/package/@supabase/s
## Framework quickstarts
- {[
- {
- title: 'Next.js',
- href: '/guides/auth/server-side/nextjs',
- description:
- 'Automatically configure Supabase in Next.js to use cookies, making your user and their session available on the client and server.',
- icon: '/docs/img/icons/nextjs-icon',
- },
- {
- title: 'SvelteKit',
- href: '/guides/auth/server-side/sveltekit',
- description:
- 'Automatically configure Supabase in SvelteKit to use cookies, making your user and their session available on the client and server.',
- icon: '/docs/img/icons/svelte-icon',
- },
- ].map((item) => {
- return (
-
-
- {item.description}
-
-
- )
- })}
+
+
+ Automatically configure Supabase in Next.js to use cookies, making your user and their session
+ available on the client and server.
+
+
+
+
+ Automatically configure Supabase in SvelteKit to use cookies, making your user and their
+ session available on the client and server.
+
+
diff --git a/apps/docs/content/guides/cli.mdx b/apps/docs/content/guides/cli.mdx
index 5c81c2414bfd4..13297eba2c2be 100644
--- a/apps/docs/content/guides/cli.mdx
+++ b/apps/docs/content/guides/cli.mdx
@@ -13,25 +13,19 @@ The Supabase CLI provides tools to develop your project locally, deploy to the S
## Resources
- {[
- {
- name: 'Supabase CLI',
- description:
- 'The Supabase CLI provides tools to develop manage your Supabase projects from your local machine.',
- href: 'https://github.com/supabase/cli',
- },
- {
- name: 'GitHub Action',
- description: ' A GitHub action for interacting with your Supabase projects using the CLI.',
- href: 'https://github.com/supabase/setup-cli',
- },
- ].map((x) => (
-
-
-
- {x.description}
-
-
-
- ))}
+
+
+
+ The Supabase CLI provides tools to develop manage your Supabase projects from your local
+ machine.
+
+
+
+
+
+
+ A GitHub action for interacting with your Supabase projects using the CLI.
+
+
+
diff --git a/apps/docs/content/guides/database/connecting-to-postgres/serverless-drivers.mdx b/apps/docs/content/guides/database/connecting-to-postgres/serverless-drivers.mdx
index eac4f7bf93acf..2459167434089 100644
--- a/apps/docs/content/guides/database/connecting-to-postgres/serverless-drivers.mdx
+++ b/apps/docs/content/guides/database/connecting-to-postgres/serverless-drivers.mdx
@@ -19,46 +19,25 @@ Choose one of these Vercel Deploy Templates which use our [Vercel Deploy Integra
- {[
- {
- title: 'supabase-js',
- hasLightIcon: true,
- href: 'https://supabase.link/nextjs-with-supabase-starter',
- description: 'A Next.js App Router template configured with cookie-based auth using Supabase, TypeScript and Tailwind CSS.'
- },
- /* { TODO: Link the correct next.js template that uses drizzle ORM with supabase database.
- hasLightIcon: true,
- href: 'https://supabase.link/nextjs-supabase-drizzle',
- description: "Simple Next.js template that uses Supabase as the database and Drizzle as the ORM.",
- },*/
- {
- title: 'Kysely',
- hasLightIcon: true,
- href: 'https://supabase.link/nextjs-supabase-kysely',
- description: 'Simple Next.js template that uses Supabase as the database and Kysely as the query builder.',
- },
- /* { TODO: figure out how to get around Prisma accelerate requirement...
- title: 'Prisma',
- hasLightIcon: true,
- href: 'https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fexamples%2Ftree%2Fmain%2Fstorage%2Fpostgres-prisma&project-name=postgres-prisma&repository-name=postgres-prisma&demo-title=Vercel%20Postgres%20%2B%20Prisma%20Next.js%20Starter&demo-description=Simple%20Next.js%20template%20that%20uses%20Vercel%20Postgres%20as%20the%20database%20and%20Prisma%20as%20the%20ORM.&demo-url=https%3A%2F%2Fpostgres-prisma.vercel.app%2F&demo-image=https%3A%2F%2Fpostgres-prisma.vercel.app%2Fopengraph-image.png&integration-ids=oac_VqOgBHqhEoFTPzGkPd7L0iH6',
- description: 'Simple Next.js template that uses Vercel Postgres as the database and Prisma as the ORM.',
- } */
- ].map((resource) => {
- return (
-
-
- {resource.description}
-
-
- )
-
-})}
-
+
+
+ A Next.js App Router template configured with cookie-based auth using Supabase, TypeScript
+ and Tailwind CSS.
+
+
+
+
+ Simple Next.js template that uses Supabase as the database and Kysely as the query builder.
+
+
@@ -75,9 +54,9 @@ POSTGRES_URL="postgres://postgres.cfcxynqnhdybqtbhjemm:[YOUR-PASSWORD]@aws-0-ap-
```ts lib/drizzle.ts
-import { pgTable, serial, text, timestamp, uniqueIndex } from 'drizzle-orm/pg-core'
-import { InferSelectModel, InferInsertModel } from 'drizzle-orm'
import { sql } from '@vercel/postgres'
+import { InferInsertModel, InferSelectModel } from 'drizzle-orm'
+import { pgTable, serial, text, timestamp, uniqueIndex } from 'drizzle-orm/pg-core'
import { drizzle } from 'drizzle-orm/vercel-postgres'
export const UsersTable = pgTable(
@@ -107,8 +86,8 @@ export const db = drizzle(sql)
```ts lib/kysely.ts
-import { Generated, ColumnType } from 'kysely'
import { createKysely } from '@vercel/postgres-kysely'
+import { ColumnType, Generated } from 'kysely'
interface UserTable {
// Columns that are generated by the database should be marked
diff --git a/apps/docs/content/guides/database/prisma.mdx b/apps/docs/content/guides/database/prisma.mdx
index 31ea39f16e54d..b72c2f8294fd5 100644
--- a/apps/docs/content/guides/database/prisma.mdx
+++ b/apps/docs/content/guides/database/prisma.mdx
@@ -78,7 +78,8 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
```bash
npm init -y
- npm install prisma typescript ts-node @types/node --save-dev
+ npm install prisma tsx @types/pg --save-dev
+ npm install @prisma/client @prisma/adapter-pg dotenv pg
npx tsc --init
@@ -87,8 +88,9 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
```bash
- pnpm init -y
- pnpm install prisma typescript ts-node @types/node --save-dev
+ pnpm init
+ pnpm install prisma tsx @types/pg --save-dev
+ pnpm install @prisma/client @prisma/adapter-pg dotenv pg
pnpx tsc --init
@@ -98,7 +100,8 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
```bash
yarn init -y
- yarn add prisma typescript ts-node @types/node --save-dev
+ yarn add prisma tsx @types/pg --save-dev
+ yarn add @prisma/client @prisma/adapter-pg dotenv pg
npx tsc --init
@@ -108,7 +111,8 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
```bash
bun init -y
- bun install prisma typescript ts-node @types/node --save-dev
+ bun install prisma tsx @types/pg --save-dev
+ bun install @prisma/client @prisma/adapter-pg dotenv pg
bunx tsc --init
@@ -168,15 +172,6 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
postgres://prisma.[PROJECT-REF]...
```
- In your schema.prisma file, edit your `datasource db` configs to reference your DIRECT_URL
- ```text schema.prisma
- datasource db {
- provider = "postgresql"
- url = env("DATABASE_URL")
- directUrl = env("DIRECT_URL")
- }
- ```
-
@@ -190,9 +185,56 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
-
+
+
+ Add `import "dotenv/config"` to the generated `prisma.config.ts`. If you are using a serverless environment, change the data source URL to `DIRECT_URL`.
+
+
+
+
+
+
+ ```ts prisma.config.ts
+ import "dotenv/config";
+ import { defineConfig, env } from "prisma/config";
+
+ export default defineConfig({
+ schema: "prisma/schema",
+ migrations: {
+ path: "prisma/migrations",
+ },
+ datasource: {
+ url: env("DATABASE_URL"),
+ },
+ });
+ ```
+
+
+ ```ts prisma.config.ts
+ import "dotenv/config";
+ import { defineConfig, env } from "prisma/config";
+
+ export default defineConfig({
+ schema: "prisma/schema",
+ migrations: {
+ path: "prisma/migrations",
+ },
+ datasource: {
+ url: env("DIRECT_URL"),
+ },
+ });
+ ```
+
+
+
+
+
+
+
+
+
- If you have already modified your Supabase database, synchronize it with your migration file. Otherwise create new tables for your database
+ If you have already modified your Supabase database, synchronize it with your migration file. Otherwise create new tables for your database, then generate the Prisma client.
@@ -232,25 +274,25 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
```bash
npx prisma migrate dev --name first_prisma_migration
-
+ npx prisma generate
```
```bash
pnpx prisma migrate dev --name first_prisma_migration
-
+ pnpx prisma generate
```
```bash
npx prisma migrate dev --name first_prisma_migration
-
+ npx prisma generate
```
```bash
bunx prisma migrate dev --name first_prisma_migration
-
+ bunx prisma generate
```
@@ -291,6 +333,7 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
```bash
npx prisma migrate resolve --applied 0_init_supabase
+ npx prisma generate
```
@@ -319,6 +362,7 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
```bash
pnpx prisma migrate resolve --applied 0_init_supabase
+ pnpx prisma generate
```
@@ -347,6 +391,7 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
```bash
npx prisma migrate resolve --applied 0_init_supabase
+ npx prisma generate
```
@@ -375,6 +420,7 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
```bash
bunx prisma migrate resolve --applied 0_init_supabase
+ bunx prisma generate
```
@@ -385,47 +431,6 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
-
-
-
- Install the Prisma client and generate its model
-
-
-
-
-
- ```sh
- npm install @prisma/client
- npx prisma generate
- ```
-
-
- ```sh
- pnpm install @prisma/client
- pnpx prisma generate
- ```
-
-
- ```sh
- yarn add @prisma/client
- npx prisma generate
- ```
-
-
- ```sh
- bun install @prisma/client
- bunx prisma generate
- ```
-
-
-
-
@@ -433,13 +438,15 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
```ts index.ts
- const { PrismaClient } = require('@prisma/client');
+ import "dotenv/config";
+ import { PrismaClient } from "./generated/prisma/client";
+ import { PrismaPg } from "@prisma/adapter-pg";
- const prisma = new PrismaClient();
+ const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
+ export const prisma = new PrismaClient({ adapter });
async function main() {
- //change to reference a table in your schema
- const val = await prisma..findMany({
+ const val = await prisma.user.findMany({
take: 10,
});
console.log(val);
@@ -452,10 +459,10 @@ If you plan to solely use Prisma instead of the Supabase Data API (PostgREST), t
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
- process.exit(1);
+ process.exit(1);
});
-
```
+
diff --git a/apps/docs/content/guides/database/prisma/prisma-troubleshooting.mdx b/apps/docs/content/guides/database/prisma/prisma-troubleshooting.mdx
index fb0f3bd25112c..ff3757e0eab09 100644
--- a/apps/docs/content/guides/database/prisma/prisma-troubleshooting.mdx
+++ b/apps/docs/content/guides/database/prisma/prisma-troubleshooting.mdx
@@ -142,18 +142,16 @@ A Prisma migration is referencing a schema it is not permitted to manage.
### Solutions: [#solutions-cross-schema-references]
-- Multi-Schema support: If the external schema isn't Supabase managed, modify your `prisma.schema` file to enable the multi-Schema preview
+- Multi-schema support: If the external schema isn't Supabase managed, list the relevant schemas on the `datasource` block in your `schema.prisma` file.
-```ts prisma.schema
+```prisma schema.prisma
generator client {
- provider = "prisma-client-js"
- previewFeatures = ["multiSchema"] //Add line
+ provider = "prisma-client"
+ output = "../generated/prisma"
}
datasource db {
provider = "postgresql"
- url = env("DATABASE_URL")
- directUrl = env("DIRECT_URL")
schemas = ["public", "other_schema"] //list out relevant schemas
}
```
diff --git a/apps/docs/content/guides/functions.mdx b/apps/docs/content/guides/functions.mdx
index fdcf0627f9ad4..718391265321a 100644
--- a/apps/docs/content/guides/functions.mdx
+++ b/apps/docs/content/guides/functions.mdx
@@ -52,156 +52,284 @@ Edge Functions are server-side TypeScript functions, distributed globally at the
Check out the [Edge Function Examples](https://github.com/supabase/supabase/tree/master/examples/edge-functions) in our GitHub repository.
- {[
- {
- name: 'With supabase-js',
- description: 'Use the Supabase client inside your Edge Function.',
- href: '/guides/functions/auth',
- },
- {
- name: 'Type-Safe SQL with Kysely',
- description:
- 'Combining Kysely with Deno Postgres gives you a convenient developer experience for interacting directly with your Postgres database.',
- href: '/guides/functions/kysely-postgres',
- },
- {
- name: 'Monitoring with Sentry',
- description: 'Monitor Edge Functions with the Sentry Deno SDK.',
- href: '/guides/functions/examples/sentry-monitoring',
- },
- {
- name: 'With CORS headers',
- description: 'Send CORS headers for invoking from the browser.',
- href: '/guides/functions/cors',
- },
- {
- name: 'React Native with Stripe',
- description: 'Full example for using Supabase and Stripe, with Expo.',
- href: 'https://github.com/supabase-community/expo-stripe-payments-with-supabase-functions',
- },
- {
- name: 'Flutter with Stripe',
- description: 'Full example for using Supabase and Stripe, with Flutter.',
- href: 'https://github.com/supabase-community/flutter-stripe-payments-with-supabase-functions',
- },
- {
- name: 'Building a RESTful Service API',
- description:
- 'Learn how to use HTTP methods and paths to build a RESTful service for managing tasks.',
- href: 'https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/restful-tasks/index.ts',
- },
- {
- name: 'Working with Supabase Storage',
- description: 'An example on reading a file from Supabase Storage.',
- href: 'https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/read-storage/index.ts',
- },
- {
- name: 'Open Graph Image Generation',
- description: 'Generate Open Graph images with Deno and Supabase Edge Functions.',
- href: '/guides/functions/examples/og-image',
- },
- {
- name: 'OG Image Generation & Storage CDN Caching',
- description: 'Cache generated images with Supabase Storage CDN.',
- href: 'https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/og-image-with-storage-cdn',
- },
- {
- name: 'Get User Location',
- description: `Get user location data from user's IP address.`,
- href: 'https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/location',
- },
- {
- name: 'Cloudflare Turnstile',
- description: `Protecting Forms with Cloudflare Turnstile.`,
- href: '/guides/functions/examples/cloudflare-turnstile',
- },
- {
- name: 'Connect to Postgres',
- description: `Connecting to Postgres from Edge Functions.`,
- href: '/guides/functions/connect-to-postgres',
- },
- {
- name: 'GitHub Actions',
- description: `Deploying Edge Functions with GitHub Actions.`,
- href: '/guides/functions/examples/github-actions',
- },
- {
- name: 'Oak Server Middleware',
- description: `Request Routing with Oak server middleware.`,
- href: 'https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/oak-server',
- },
- {
- name: 'Hugging Face',
- description: `Access 100,000+ Machine Learning models.`,
- href: '/guides/ai/examples/huggingface-image-captioning',
- },
- {
- name: 'Amazon Bedrock',
- description: `Amazon Bedrock Image Generator`,
- href: '/guides/functions/examples/amazon-bedrock-image-generator',
- },
- {
- name: 'OpenAI',
- description: `Using OpenAI in Edge Functions.`,
- href: '/guides/ai/examples/openai',
- },
- {
- name: 'Stripe Webhooks',
- description: `Handling signed Stripe Webhooks with Edge Functions.`,
- href: '/guides/functions/examples/stripe-webhooks',
- },
- {
- name: 'Send emails',
- description: `Send emails in Edge Functions with Resend.`,
- href: '/guides/functions/examples/send-emails',
- },
- {
- name: 'Web Stream',
- description: `Server-Sent Events in Edge Functions.`,
- href: 'https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/streams',
- },
- {
- name: 'Puppeteer',
- description: `Generate screenshots with Puppeteer.`,
- href: '/guides/functions/examples/screenshots',
- },
- {
- name: 'Discord Bot',
- description: `Building a Slash Command Discord Bot with Edge Functions.`,
- href: '/guides/functions/examples/discord-bot',
- },
- {
- name: 'Telegram Bot',
- description: `Building a Telegram Bot with Edge Functions.`,
- href: '/guides/functions/examples/telegram-bot',
- },
- {
- name: 'Upload File',
- description: `Process multipart/form-data.`,
- href: 'https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/file-upload-storage',
- },
- {
- name: 'Upstash Redis',
- description: `Build an Edge Functions Counter with Upstash Redis.`,
- href: '/guides/functions/examples/upstash-redis',
- },
- {
- name: 'Rate Limiting',
- description: `Rate Limiting Edge Functions with Upstash Redis.`,
- href: '/guides/functions/examples/rate-limiting',
- },
- {
- name: 'Slack Bot Mention Edge Function',
- description: `Slack Bot handling Slack mentions in Edge Function`,
- href: '/guides/functions/examples/slack-bot-mention',
- },
- ].map((x) => (
-
-
-
- {x.description}
-
-
-
- ))}
+
+
+
+ Use the Supabase client inside your Edge Function.
+
+
+
+
+
+
+ Combining Kysely with Deno Postgres gives you a convenient developer experience for
+ interacting directly with your Postgres database.
+
+
+
+
+
+
+ Monitor Edge Functions with the Sentry Deno SDK.
+
+
+
+
+
+
+ Send CORS headers for invoking from the browser.
+
+
+
+
+
+
+ Full example for using Supabase and Stripe, with Expo.
+
+
+
+
+
+
+ Full example for using Supabase and Stripe, with Flutter.
+
+
+
+
+
+
+ Learn how to use HTTP methods and paths to build a RESTful service for managing tasks.
+
+
+
+
+
+
+ An example on reading a file from Supabase Storage.
+
+
+
+
+
+
+ Generate Open Graph images with Deno and Supabase Edge Functions.
+
+
+
- {[
- {
- title: 'Build with AI tools',
- description: 'Develop with Supabase AI-first using plugins, MCP, and skills.',
- hasLightIcon: true,
- href: '/guides/ai',
- },
- {
- title: 'API Keys',
- hasLightIcon: true,
- href: '/guides/getting-started/api-keys',
- description: 'Learn about the different API keys in Supabase and how to use them.',
- },
- {
- title: 'Local Development',
- hasLightIcon: true,
- href: '/guides/cli/getting-started',
- description: 'Use the Supabase CLI to develop locally and collaborate between teams.',
- }
- ].map((resource) => {
- return (
-
-
- {resource.description}
-
-
- )
-
-})}
-
-
+
+
+
+ Develop with Supabase AI-first using plugins, MCP, and skills.
+
+
+
+
+ Learn about the different API keys in Supabase and how to use them.
+
+
+
+
+ Use the Supabase CLI to develop locally and collaborate between teams.
+
+
+
- {[
- {
- title: 'React',
- href: '/guides/getting-started/quickstarts/reactjs',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a React app.',
- icon: '/docs/img/icons/react-icon',
- enabled: isFeatureEnabled('docs:framework_quickstarts'),
- },
- {
- title: 'Next.js',
- href: '/guides/getting-started/quickstarts/nextjs',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Next.js app.',
- icon: '/docs/img/icons/nextjs-icon',
- hasLightIcon: true,
- enabled: isFeatureEnabled('docs:framework_quickstarts'),
- },
- {
- title: 'Nuxt',
- href: '/guides/getting-started/quickstarts/nuxtjs',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Nuxt app.',
- icon: '/docs/img/icons/nuxt-icon',
- enabled: isFeatureEnabled('docs:framework_quickstarts'),
- },
- {
- title: 'Hono',
- href: '/guides/getting-started/quickstarts/hono',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, secure it with auth, and query the data from a Hono app.',
- icon: '/docs/img/icons/hono-icon',
- enabled: isFeatureEnabled('docs:framework_quickstarts'),
- },
- {
- title: 'RedwoodJS',
- href: '/guides/getting-started/quickstarts/redwoodjs',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database using Prisma migration and seeds, and query the data from a RedwoodJS app.',
- icon: '/docs/img/icons/redwood-icon',
- enabled: isFeatureEnabled('docs:framework_quickstarts'),
- },
- {
- title: 'Flutter',
- href: '/guides/getting-started/quickstarts/flutter',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Flutter app.',
- icon: '/docs/img/icons/flutter-icon',
- enabled: isFeatureEnabled('sdk:dart'),
- },
- {
- title: 'iOS SwiftUI',
- href: '/guides/getting-started/quickstarts/ios-swiftui',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from an iOS app.',
- icon: '/docs/img/icons/swift-icon',
- enabled: isFeatureEnabled('sdk:swift'),
- },
- {
- title: 'Android Kotlin',
- href: '/guides/getting-started/quickstarts/kotlin',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from an Android Kotlin app.',
- icon: '/docs/img/icons/kotlin-icon',
- enabled: isFeatureEnabled('sdk:kotlin'),
- },
- {
- title: 'SvelteKit',
- href: '/guides/getting-started/quickstarts/sveltekit',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a SvelteKit app.',
- icon: '/docs/img/icons/svelte-icon',
- enabled: isFeatureEnabled('docs:framework_quickstarts'),
- },
- {
- title: 'SolidJS',
- href: '/guides/getting-started/quickstarts/solidjs',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a SolidJS app.',
- icon: '/docs/img/icons/solidjs-icon',
- enabled: isFeatureEnabled('docs:framework_quickstarts'),
- },
- {
- title: 'Vue',
- href: '/guides/getting-started/quickstarts/vue',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Vue app.',
- icon: '/docs/img/icons/vuejs-icon',
- enabled: isFeatureEnabled('docs:framework_quickstarts'),
- },
- {
- title: 'TanStack Start',
- href: '/guides/getting-started/quickstarts/tanstack',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a TanStack Start app.',
- icon: '/docs/img/icons/tanstack-icon',
- hasLightIcon: true,
- enabled: isFeatureEnabled('docs:framework_quickstarts'),
- },
- {
- title: 'Refine',
- href: '/guides/getting-started/quickstarts/refine',
- description:
- 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Refine app.',
- icon: '/docs/img/icons/refine-icon',
- enabled: isFeatureEnabled('docs:framework_quickstarts'),
- },
- ]
- .filter((item) => item.enabled !== false)
- .map((item) => {
- return (
-
-
- {item.description}
-
-
- )
- })}
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from a React app.
+
+
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from a Next.js app.
+
+
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from a Nuxt app.
+
+
+
+
+ Learn how to create a Supabase project, add some sample data to your database, secure it with
+ auth, and query the data from a Hono app.
+
+
+
+
+ Learn how to create a Supabase project, add some sample data to your database using Prisma
+ migration and seeds, and query the data from a RedwoodJS app.
+
+
+ <$Show if="sdk:dart">
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from a Flutter app.
+
+
+ $Show>
+ <$Show if="sdk:swift">
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from an iOS app.
+
+
+ $Show>
+ <$Show if="sdk:kotlin">
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from an Android Kotlin app.
+
+
+ $Show>
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from a SvelteKit app.
+
+
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from a SolidJS app.
+
+
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from a Vue app.
+
+
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from a TanStack Start app.
+
+
+
+
+ Learn how to create a Supabase project, add some sample data to your database, and query the
+ data from a Refine app.
+
+
- {
- [
- {
- title: 'Next.js',
- href: '/guides/getting-started/tutorials/with-nextjs',
- description:
- 'Learn how to build a user management app with Next.js and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/nextjs-icon',
- hasLightIcon: true,
- },
- {
- title: 'React',
- href: '/guides/getting-started/tutorials/with-react',
- description:
- 'Learn how to build a user management app with React and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/react-icon',
- },
- {
- title: 'Vue 3',
- href: '/guides/getting-started/tutorials/with-vue-3',
- description:
- 'Learn how to build a user management app with Vue 3 and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/vuejs-icon',
- },
- {
- title: 'Nuxt 3',
- href: '/guides/getting-started/tutorials/with-nuxt-3',
- description:
- 'Learn how to build a user management app with Nuxt 3 and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/nuxt-icon',
- },
- {
- title: 'Angular',
- href: '/guides/getting-started/tutorials/with-angular',
- description:
- 'Learn how to build a user management app with Angular and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/angular-icon',
- },
- {
- title: 'RedwoodJS',
- href: '/guides/getting-started/tutorials/with-redwoodjs',
- description:
- 'Learn how to build a user management app with RedwoodJS and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/redwood-icon',
- },
- {
- title: 'Svelte',
- href: '/guides/getting-started/tutorials/with-svelte',
- description:
- 'Learn how to build a user management app with Svelte and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/svelte-icon',
- },
- {
- title: 'SvelteKit',
- href: '/guides/getting-started/tutorials/with-sveltekit',
- description:
- 'Learn how to build a user management app with SvelteKit and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/svelte-icon',
- },
- {
- title: 'Refine',
- href: '/guides/getting-started/tutorials/with-refine',
- description:
- 'Learn how to build a user management app with Refine and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/refine-icon',
- }
- ]
-.map((item) => {
- return (
-
-
- {item.description}
-
-
- )
-
-})}
-
+
+
+ Learn how to build a user management app with Next.js and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to build a user management app with React and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to build a user management app with Vue 3 and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to build a user management app with Nuxt 3 and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to build a user management app with Angular and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to build a user management app with RedwoodJS and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to build a user management app with Svelte and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to build a user management app with SvelteKit and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to build a user management app with Refine and Supabase Database, Auth, and Storage functionality.
+
+
$Show>
@@ -327,90 +335,105 @@ hideToc: true
### Mobile tutorials
- {[
- {
- title: 'Flutter',
- href: '/guides/getting-started/tutorials/with-flutter',
- description:
- 'Learn how to build a user management app with Flutter and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/flutter-icon',
- enabled: isFeatureEnabled('sdk:dart')
- },
- {
- title: 'Expo React Native',
- href: '/guides/getting-started/tutorials/with-expo-react-native',
- description:
- 'Learn how to build a user management app with Expo React Native and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/expo-icon',
- hasLightIcon: true,
- enabled: true
- },
- {
- title: 'Expo React Native Social Auth',
- href: '/guides/getting-started/tutorials/with-expo-react-native-social-auth',
- description:
- 'Learn how to implement social authentication in an app with Expo React Native and Supabase Database and Auth functionality.',
- icon: '/docs/img/icons/expo-icon',
- hasLightIcon: true
- },
- {
- title: 'Android Kotlin',
- href: '/guides/getting-started/tutorials/with-kotlin',
- description:
- 'Learn how to build a product management app with Android and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/kotlin-icon',
- enabled: isFeatureEnabled('sdk:kotlin')
- },
- {
- title: 'iOS Swift',
- href: '/guides/getting-started/tutorials/with-swift',
- description:
- 'Learn how to build a user management app with iOS and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/swift-icon',
- enabled: isFeatureEnabled('sdk:swift')
- },
- {
- title: 'Ionic React',
- href: '/guides/getting-started/tutorials/with-ionic-react',
- description:
- 'Learn how to build a user management app with Ionic React and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/ionic-icon',
- enabled: true
- },
- {
- title: 'Ionic Vue',
- href: '/guides/getting-started/tutorials/with-ionic-vue',
- description:
- 'Learn how to build a user management app with Ionic Vue and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/ionic-icon',
- enabled: true
- },
- {
- title: 'Ionic Angular',
- href: '/guides/getting-started/tutorials/with-ionic-angular',
- description:
- 'Learn how to build a user management app with Ionic Angular and Supabase Database, Auth, and Storage functionality.',
- icon: '/docs/img/icons/ionic-icon',
- enabled: true
- }
- ]
-.filter((item) => item.enabled !== false)
-.map((item) => {
- return (
-
-
- {item.description}
-
-
- )
-
-})}
-
+ <$Show if="sdk:dart">
+
+
+ Learn how to build a user management app with Flutter and Supabase Database, Auth, and Storage functionality.
+
+
+ $Show>
+
+
+ Learn how to build a user management app with Expo React Native and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to implement social authentication in an app with Expo React Native and Supabase Database and Auth functionality.
+
+
+ <$Show if="sdk:kotlin">
+
+
+ Learn how to build a product management app with Android and Supabase Database, Auth, and Storage functionality.
+
+
+ $Show>
+ <$Show if="sdk:swift">
+
+
+ Learn how to build a user management app with iOS and Supabase Database, Auth, and Storage functionality.
+
+
+ $Show>
+
+
+ Learn how to build a user management app with Ionic React and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to build a user management app with Ionic Vue and Supabase Database, Auth, and Storage functionality.
+
+
+
+
+ Learn how to build a user management app with Ionic Angular and Supabase Database, Auth, and Storage functionality.
+
+
$Show>
diff --git a/apps/docs/content/guides/platform/temporary-access.mdx b/apps/docs/content/guides/platform/temporary-access.mdx
new file mode 100644
index 0000000000000..32e067c380c16
--- /dev/null
+++ b/apps/docs/content/guides/platform/temporary-access.mdx
@@ -0,0 +1,118 @@
+---
+title: 'Temporary access'
+description: 'Enable temporary access for short-lived database connections tied to a Supabase user.'
+---
+
+Your Supabase project supports connecting to the Postgres database using either your Supabase API token (Personal Access Token) or your current dashboard session token (JWT). This is called temporary access, as the authentication tokens can be short-lived and tied directly to a specific Supabase user. Temporary access is disabled by default.
+
+Enabling temporary access only applies to connections to Postgres and Supavisor ("Connection Pooler"); all HTTP APIs offered by Supabase (e.g., PostgREST, Storage, Auth) require authentication tokens specific to the service and are independent of the Supabase platform user(s).
+
+
+
+Projects need to be at least on Postgres 17.6.1.081 (or higher) to enable temporary access. You can find the Postgres version of your project on the [infrastructure settings](/dashboard/project/_/settings/infrastructure) page. If your project is on an older version, you will need to [upgrade](/docs/guides/platform/upgrading) to use this feature.
+
+
+
+## Manage temporary access via the dashboard
+
+The easiest way to manage temporary access is via the "Enable temporary access" settings section in [Database Settings page](/dashboard/project/_/database/settings) of the dashboard.
+
+## Manage temporary access via the Management API
+
+You can also manage temporary access using the Management API:
+
+```bash
+# Get your access token from https://supabase.com/dashboard/account/tokens
+export SUPABASE_MANAGEMENT_API_TOKEN="your-access-token"
+export PROJECT_REF="your-project-ref"
+
+# Get current temporary access status
+curl -X GET "https://api.supabase.com/v1/projects/$PROJECT_REF/database/jit-access" \
+ -H "Authorization: Bearer $SUPABASE_MANAGEMENT_API_TOKEN"
+
+# Enable temporary access
+curl -X PUT "https://api.supabase.com/v1/projects/$PROJECT_REF/database/jit-access" \
+ -H "Authorization: Bearer $SUPABASE_MANAGEMENT_API_TOKEN" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "state":"enabled"
+ }'
+
+# Disable temporary access
+curl -X PUT "https://api.supabase.com/v1/projects/$PROJECT_REF/database/jit-access" \
+ -H "Authorization: Bearer $SUPABASE_MANAGEMENT_API_TOKEN" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "state":"disabled"
+ }'
+```
+
+## Configure user access
+
+Once temporary access has been enabled, project users must be authorized and mapped to Postgres roles they are allowed to access. Each user can be authorized to "assume" one or more Postgres roles using temporary access.
+
+When a user is authorized to assume a Postgres role, the user's access token (Personal Access Token (PAT) or Scoped PAT) will be used as the password for the Postgres role.
+
+
+
+Postgres roles can still be accessed using the password configured on the role. This allows long-lived service connections to continue using the existing credentials.
+
+Temporary access authentication only applies for Supabase project users authenticating to the database, and assuming the given Postgres role. No new roles or users are created in the Postgres database and the assumed role's permissions will still apply.
+
+
+
+### Apply temporary access restrictions
+
+A user's temporary access can also be restricted to a validity period, after which their temporary access will expire and even though the access token is still valid, the database will reject the connection.
+
+IP address restrictions can also be applied, ensuring that temporary access will only be authorized from allowed network ranges (IPv4 and/or IPv6).
+
+#### Applying restrictions with the management API
+
+Restrictions can also be applied through the Management API.
+
+```bash
+# Get your access token from https://supabase.com/dashboard/account/tokens
+export SUPABASE_MANAGEMENT_API_TOKEN="your-access-token"
+export PROJECT_REF="your-project-ref"
+
+# Restrict temporary access to IPv4 ranges and expiry date
+# user_id is the gotrue_id of the user with access to the project
+curl -X PUT "https://api.supabase.com/v1/projects/$PROJECT_REF/database/jit" \
+ -H "Authorization: Bearer $SUPABASE_MANAGEMENT_API_TOKEN" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "user_id": "00000000-1111-2222-3333-444444444444",
+ "user_roles": [
+ {
+ "role": "postgres",
+ "allowed_networks": {
+ "allowed_cidrs": [{ "cidr": "176.1.12.1/32" }]
+ },
+ "expires_at": 1758721065775
+ }
+ ]
+ }'
+```
+
+## Using temporary access
+
+To log in to the database using temporary access, existing connection strings can be used and only the password needs to be changed to the user's API or dashboard token.
+
+For example, if a user has been authorized to assume the `postgres` role:
+
+```
+psql 'postgres://postgres:sbp_111222333aaabbbccc@db.{project-ref}.supabase.co/postgres'
+```
+
+Since Supabase API tokens can be used, it is also possible to generate API tokens for services you don't want to share your Postgres role password with (for example a GitHub Action). The API token can be configured with an expiry time and temporary access-specific restrictions can also be applied.
+
+Connecting via the shared connection pooler requires the addition of a new connection option. This can be applied either directly in the connection URI or as `conninfo` (easier to read):
+
+```
+# directly in the URI
+psql 'postgres://postgres.{project-ref}:sbp_111222333aaabbbccc@aws-1-us-west-1.pooler.supabase.com:5432/postgres?options=-c%20jit%3don'
+
+# or as a connection info string
+psql "host=aws-1-us-west-1.pooler.supabase.com user=postgres.{project-ref} options='-c jit=on'"
+```
diff --git a/apps/docs/content/guides/realtime.mdx b/apps/docs/content/guides/realtime.mdx
index 9a4331929cb1f..cd79fccadff5d 100644
--- a/apps/docs/content/guides/realtime.mdx
+++ b/apps/docs/content/guides/realtime.mdx
@@ -25,35 +25,35 @@ Check the [Getting Started](/docs/guides/realtime/getting_started) guide to get
## Examples
+
+
+ Showcase application displaying cursor movements and chat messages using Broadcast.
+
+
+
+
+
+
+ Supabase UI chat component using Broadcast to send message between users.
+
+
+
+
+
+
+ Supabase UI avatar stack component using Presence to track connected users.
+
+
+
+
+
+
+ Supabase UI realtime cursor component using Broadcast to share users' cursors to build
+ collaborative applications.
+
-))}
-
## Resources
@@ -61,22 +61,19 @@ Check the [Getting Started](/docs/guides/realtime/getting_started) guide to get
Find the source code and documentation in the Supabase GitHub repository.
- {
- [
- {
- title: 'Examples',
- hasLightIcon: true,
- href: '/guides/resources/examples',
- description: 'Official GitHub examples, curated content from the community, and more.',
- },
- {
- title: 'Glossary',
- hasLightIcon: true,
- href: '/guides/resources/glossary',
- description: 'Definitions for terminology and acronyms used in the Supabase documentation.',
- }
- ]
-.map((resource) => {
- return (
-
-
- {resource.description}
-
-
- )
-
-})}
-
-
+
+
+
+ Official GitHub examples, curated content from the community, and more.
+
+
+
+
+ Definitions for terminology and acronyms used in the Supabase documentation.
+
+
+
@@ -53,88 +32,159 @@ hideToc: true
-
- {
- [
- {
- title: 'Auth0',
- icon: '/docs/img/icons/auth0-icon',
- href: '/guides/resources/migrating-to-supabase/auth0',
- description: 'Move your auth users from Auth0 to a Supabase project.',
- hasLightIcon: true,
- },
- {
- title: 'Firebase Auth',
- icon: '/docs/img/icons/firebase-icon',
- href: '/guides/resources/migrating-to-supabase/firebase-auth',
- description: 'Move your auth users from a Firebase project to a Supabase project.',
- },
- {
- title: 'Firestore Data',
- icon: '/docs/img/icons/firebase-icon',
- href: '/guides/resources/migrating-to-supabase/firestore-data',
- description: 'Migrate the contents of a Firestore collection to a single Postgres table.',
- },
- {
- title: 'Firebase Storage',
- icon: '/docs/img/icons/firebase-icon',
- href: '/guides/resources/migrating-to-supabase/firebase-storage',
- description: 'Convert your Firebase Storage files to Supabase Storage.'
- },
- {
- title: 'Heroku',
- icon: '/docs/img/icons/heroku-icon',
- href: '/guides/resources/migrating-to-supabase/heroku',
- description: 'Migrate your Heroku Postgres database to Supabase.'
- },
- {
- title: 'Render',
- icon: '/docs/img/icons/render-icon',
- href: '/guides/resources/migrating-to-supabase/render',
- description: 'Migrate your Render Postgres database to Supabase.'
- },
- {
- title: 'Amazon RDS',
- icon: '/docs/img/icons/aws-rds-icon',
- href: '/guides/resources/migrating-to-supabase/amazon-rds',
- description: 'Migrate your Amazon RDS database to Supabase.'
- },
- {
- title: 'Postgres',
- icon: '/docs/img/icons/postgres-icon',
- href: '/guides/resources/migrating-to-supabase/postgres',
- description: 'Migrate your Postgres database to Supabase.'
- },
- {
- title: 'MySQL',
- icon: '/docs/img/icons/mysql-icon',
- href: '/guides/resources/migrating-to-supabase/mysql',
- description: 'Migrate your MySQL database to Supabase.'
- },
- {
- title: 'Microsoft SQL Server',
- icon: '/docs/img/icons/mssql-icon',
- href: '/guides/resources/migrating-to-supabase/mssql',
- description: 'Migrate your Microsoft SQL Server database to Supabase.'
- }
- ]
-.map((product) => {
- return (
-
-
- {product.description}
-
-
- )
-
-})}
-
-
+
+
+
+ Move your auth users from Auth0 to a Supabase project.
+
+
+
+
+ Move your auth users from a Firebase project to a Supabase project.
+
+
+
+
+ Migrate the contents of a Firestore collection to a single Postgres table.
+
+
+
+
+ Convert your Firebase Storage files to Supabase Storage.
+
+
+
+
+ Migrate your Heroku Postgres database to Supabase.
+
+
+
+
+ Migrate your Render Postgres database to Supabase.
+
+
+
+
+ Migrate your Amazon RDS database to Supabase.
+
+
+
+
+ Migrate your Postgres database to Supabase.
+
+
+
+
+ Migrate your MySQL database to Supabase.
+
+
+
+
+ Migrate your Microsoft SQL Server database to Supabase.
+
+
+
@@ -145,57 +195,64 @@ hideToc: true
-
- {
- [
- {
- title: 'Managing Indexes',
- hasLightIcon: true,
- href: '/guides/database/postgres/indexes',
- description: 'Improve query performance using various index types in Postgres.'
- },
- {
- title: 'Cascade Deletes',
- hasLightIcon: true,
- href: '/guides/database/postgres/cascade-deletes',
- description: 'Understand the types of foreign key constraint deletes.'
- },
- {
- title: 'Drop all tables in schema',
- hasLightIcon: true,
- href: '/guides/database/postgres/dropping-all-tables-in-schema',
- description: 'Delete all tables in a given schema.'
- },
- {
- title: 'Select first row per group',
- hasLightIcon: true,
- href: '/guides/database/postgres/first-row-in-group',
- description: 'Retrieve the first row in each distinct group.'
- },
- {
- title: 'Print Postgres version',
- hasLightIcon: true,
- href: '/guides/database/postgres/which-version-of-postgres',
- description: 'Find out which version of Postgres you are running.'
- }
- ]
-.map((resource) => {
- return (
-
-
- {resource.description}
-
-
- )
-
-})}
-
-
+
+
+
+ Improve query performance using various index types in Postgres.
+
+
+
+
+ Understand the types of foreign key constraint deletes.
+
+
+
+
+ Delete all tables in a given schema.
+
+
+
+
+ Retrieve the first row in each distinct group.
+
+
+
+
+ Find out which version of Postgres you are running.
+
+
+
diff --git a/apps/docs/content/guides/self-hosting.mdx b/apps/docs/content/guides/self-hosting.mdx
index 9f16ea9ba9994..f5923055c7bbb 100644
--- a/apps/docs/content/guides/self-hosting.mdx
+++ b/apps/docs/content/guides/self-hosting.mdx
@@ -34,23 +34,20 @@ The fastest and recommended way to self-host Supabase is to use Docker.
There are several other options to deploy Supabase. If you're interested in helping these projects, visit our [Community](/contribute) page.
- {selfHostingCommunity.map((x) => (
-
-
-
- {x.name}
-
- }
- >
- {x.description}
-
-
-
-
-))}
-
+
+
+ Kubernetes}>
+ Helm charts to deploy a Supabase on Kubernetes.
+
+
+
+
+
+ Traefik}>
+ A self-hosted Supabase setup with Traefik as a reverse proxy.
+
+
+
## About self-hosting
diff --git a/apps/docs/content/guides/storage.mdx b/apps/docs/content/guides/storage.mdx
index 51b8a466b64b0..81643f11439c4 100644
--- a/apps/docs/content/guides/storage.mdx
+++ b/apps/docs/content/guides/storage.mdx
@@ -71,15 +71,20 @@ Specialized storage for vector embeddings and similarity search operations. Desi
Check out all of the Storage [templates and examples](https://github.com/supabase/supabase/tree/master/examples/storage) in our GitHub repository.
- {storageExamples.map((x) => (
-
-
-
- {x.description}
-
-
-
- ))}
+
+
+
+ Use Uppy to upload files to Supabase Storage using the TUS protocol (resumable uploads).
+
+
+
## Resources
@@ -87,22 +92,16 @@ Check out all of the Storage [templates and examples](https://github.com/supabas
Find the source code and documentation in the Supabase GitHub repository.
+
+
+ See the Swagger Documentation for Supabase Storage.
+
+
+
diff --git a/apps/docs/features/docs/MdxBase.tsx b/apps/docs/features/docs/MdxBase.tsx
index 0123fb24108ca..d356112565559 100644
--- a/apps/docs/features/docs/MdxBase.tsx
+++ b/apps/docs/features/docs/MdxBase.tsx
@@ -1,6 +1,5 @@
import { preprocessMdxWithDefaults } from '~/features/directives/utils'
import { components } from '~/features/docs/MdxBase.shared'
-import { guidesData } from '~/lib/guidesData'
import { SerializeOptions } from '~/types/next-mdx-remote-serialize'
import { isFeatureEnabled } from 'common'
import { MDXRemote } from 'next-mdx-remote-client/rsc'
@@ -39,7 +38,7 @@ const MDXRemoteBase = async ({
} = mdxOptions
const finalOptions = {
- scope: { isFeatureEnabled, ...guidesData },
+ scope: { isFeatureEnabled },
...mdxOptions,
...otherOptions,
mdxOptions: {
diff --git a/apps/docs/features/docs/Reference.apiPage.tsx b/apps/docs/features/docs/Reference.apiPage.tsx
index e1bd542dc98dd..3e77558f3e6a0 100644
--- a/apps/docs/features/docs/Reference.apiPage.tsx
+++ b/apps/docs/features/docs/Reference.apiPage.tsx
@@ -9,7 +9,7 @@ import { SidebarSkeleton } from '~/layouts/MainSkeleton'
export async function ApiReferencePage() {
return (
-
+
+
diff --git a/apps/docs/features/docs/Reference.navigation.client.tsx b/apps/docs/features/docs/Reference.navigation.client.tsx
index 3e991fd6dc1c7..75e2ea65fb2c1 100644
--- a/apps/docs/features/docs/Reference.navigation.client.tsx
+++ b/apps/docs/features/docs/Reference.navigation.client.tsx
@@ -6,6 +6,7 @@ import { BASE_PATH } from '~/lib/constants'
import { debounce } from 'lodash-es'
import { ChevronUp } from 'lucide-react'
import Link from 'next/link'
+import { usePathname } from 'next/navigation'
import { Collapsible } from 'radix-ui'
import type { HTMLAttributes, MouseEvent, PropsWithChildren } from 'react'
import {
@@ -36,7 +37,6 @@ function subscribeToPathname(callback: () => void) {
if (patchCount === 0) {
window.addEventListener('popstate', notifyPathnameListeners)
- window.addEventListener('hashchange', notifyPathnameListeners)
originalPushState = history.pushState.bind(history)
history.pushState = (...args) => {
@@ -58,7 +58,6 @@ function subscribeToPathname(callback: () => void) {
if (patchCount === 0) {
window.removeEventListener('popstate', notifyPathnameListeners)
- window.removeEventListener('hashchange', notifyPathnameListeners)
history.pushState = originalPushState!
history.replaceState = originalReplaceState!
originalPushState = null
@@ -67,29 +66,40 @@ function subscribeToPathname(callback: () => void) {
}
}
-function getLocation() {
+function getPathname() {
if (typeof window === 'undefined') return ''
const pathname = window.location.pathname
- const strippedPathname = pathname.startsWith(BASE_PATH)
- ? pathname.slice(BASE_PATH.length)
- : pathname
- return `${strippedPathname}${window.location.hash}`
+ return pathname.startsWith(BASE_PATH) ? pathname.slice(BASE_PATH.length) : pathname
}
-function getServerLocation() {
+function getServerPathname() {
return ''
}
-function useCurrentLocation() {
- return useSyncExternalStore(subscribeToPathname, getLocation, getServerLocation)
+function useCurrentPathname() {
+ return useSyncExternalStore(subscribeToPathname, getPathname, getServerPathname)
}
-export function ReferenceContentScrollHandler({ children }: PropsWithChildren) {
+export function ReferenceContentScrollHandler({
+ libPath,
+ version,
+ isLatestVersion,
+ children,
+}: PropsWithChildren<{
+ libPath: string
+ version: string
+ isLatestVersion: boolean
+}>) {
const [initiallyScrolled, setInitiallyScrolled] = useState(false)
+ const pathname = usePathname()
+
useEffect(() => {
if (!initiallyScrolled) {
- const initialSelectedSection = window.location.hash.replace(/^#/, '')
+ const initialSelectedSection = pathname.replace(
+ `/reference/${libPath}/${isLatestVersion ? '' : `${version}/`}`,
+ ''
+ )
if (initialSelectedSection) {
const section = document.getElementById(initialSelectedSection)
if (section) {
@@ -100,7 +110,7 @@ export function ReferenceContentScrollHandler({ children }: PropsWithChildren) {
setInitiallyScrolled(true)
}
- }, [initiallyScrolled])
+ }, [pathname, libPath, version, isLatestVersion, initiallyScrolled])
return (
@@ -167,7 +177,7 @@ export function ReferenceNavigationScrollHandler({
}
function deriveHref(basePath: string, section: AbbrevApiReferenceSection) {
- return 'slug' in section ? `${basePath}#${section.slug}` : ''
+ return 'slug' in section ? `${basePath}/${section.slug}` : ''
}
function getLinkStyles(isActive: boolean, className?: string) {
@@ -237,10 +247,10 @@ export function RefLink({
}) {
const ref = useRef(null)
- const location = useCurrentLocation()
+ const pathname = useCurrentPathname()
const href = deriveHref(basePath, section)
const isActive =
- location === href || (location === basePath && href.replace(basePath, '') === '#introduction')
+ pathname === href || (pathname === basePath && href.replace(basePath, '') === '/introduction')
useEffect(() => {
if (ref.current) {
@@ -283,15 +293,15 @@ export function RefLink({
function useCompoundRefLinkActive(basePath: string, section: AbbrevApiReferenceSection) {
const [open, _setOpen] = useState(false)
- const location = useCurrentLocation()
+ const pathname = useCurrentPathname()
const parentHref = deriveHref(basePath, section)
- const isParentActive = location === parentHref
+ const isParentActive = pathname === parentHref
const childHrefs = useMemo(
() => new Set((section.items || []).map((item) => deriveHref(basePath, item))),
[basePath, section]
)
- const isChildActive = childHrefs.has(location)
+ const isChildActive = childHrefs.has(pathname)
const isActive = isParentActive || isChildActive
diff --git a/apps/docs/features/docs/Reference.sdkPage.tsx b/apps/docs/features/docs/Reference.sdkPage.tsx
index 5d095d520345c..9f03d453bde2c 100644
--- a/apps/docs/features/docs/Reference.sdkPage.tsx
+++ b/apps/docs/features/docs/Reference.sdkPage.tsx
@@ -21,7 +21,11 @@ export async function ClientSdkReferencePage({ sdkId, libVersion }: ClientSdkRef
const menuData = NavItems[libraryMeta.meta[libVersion].libId]
return (
-
+
{subcommandDetails.title}
diff --git a/apps/docs/features/docs/Reference.selfHostingPage.tsx b/apps/docs/features/docs/Reference.selfHostingPage.tsx
index 7fad5fefc0f0c..53773af35149a 100644
--- a/apps/docs/features/docs/Reference.selfHostingPage.tsx
+++ b/apps/docs/features/docs/Reference.selfHostingPage.tsx
@@ -48,7 +48,7 @@ export async function SelfHostingReferencePage({
const name = REFERENCES[servicePath.replaceAll('-', '_')].name
return (
-
+ ...}` forms.
+ * For JSX titles, strips inline tags and collapses whitespace so the text
+ * content remains.
*/
-function convertResourceLists(content: string): string {
- return content.replace(/\{\s*\[\s*\{[\s\S]*?\},?\s*\][\s\S]*?\}\)\}/g, (block) => {
- const arrMatch = block.match(/\[([\s\S]+?)\]\s*\.(?:filter|map)\b/)
- if (!arrMatch) return block
-
- // Collect top-level { ... } object literals from the array body.
- const arr = arrMatch[1]
- const objs: string[] = []
+function extractTitleAttr(attrs: string): string | null {
+ const strMatch = attrs.match(/\btitle=(?:"([^"]+)"|'([^']+)')/)
+ if (strMatch) return strMatch[1] ?? strMatch[2]
+
+ const exprIdx = attrs.indexOf('title={')
+ if (exprIdx === -1) return null
+
+ let i = exprIdx + 'title={'.length
+ const inner: string[] = []
+ let depth = 1
+ while (i < attrs.length && depth > 0) {
+ const ch = attrs[i]
+ if (ch === '{') depth++
+ else if (ch === '}') {
+ depth--
+ if (depth === 0) break
+ }
+ inner.push(ch)
+ i++
+ }
+ return inner
+ .join('')
+ .replace(/<[^>]+>/g, ' ')
+ .replace(/\s+/g, ' ')
+ .trim()
+}
+
+/**
+ * Converts `desc`
+ * blocks into markdown bullet lines: `- [title](href). description`. Without
+ * this, the rendered output keeps prop syntax (className, passHref, etc.) since
+ * stripping JSX tags discards inner text from props but leaves panel children
+ * floating without context. Applied to all guides so resource-card grids render
+ * consistently in the markdown view.
+ */
+function convertLinkPanels(content: string): string {
+ return content.replace(/([\s\S]*?)<\/Link>/g, (full, linkAttrs, body) => {
+ const hrefMatch = linkAttrs.match(/\bhref="([^"]+)"/)
+ if (!hrefMatch) return full
+ const href = hrefMatch[1]
+
+ const panelOpen = body.match(/<(GlassPanel|IconPanel)\b/)
+ if (!panelOpen) return full
+ const panelName = panelOpen[1]
+ const panelStart = panelOpen.index ?? 0
+
+ // Walk past the opening tag, respecting JSX expression braces so attribute
+ // values like `title={...}` don't terminate parsing early.
+ let i = panelStart + panelOpen[0].length
let depth = 0
- let start = -1
- for (let i = 0; i < arr.length; i++) {
- if (arr[i] === '{') {
- if (depth === 0) start = i
- depth++
- } else if (arr[i] === '}' && --depth === 0 && start !== -1) {
- objs.push(arr.slice(start, i + 1))
- start = -1
- }
+ while (i < body.length) {
+ const ch = body[i]
+ if (ch === '{') depth++
+ else if (ch === '}') depth--
+ else if (ch === '>' && depth === 0) break
+ i++
}
+ if (i >= body.length) return full
+
+ const panelAttrs = body.slice(panelStart + panelOpen[0].length, i)
+ const closingTag = `${panelName}>`
+ const closeIdx = body.indexOf(closingTag, i)
+ if (closeIdx === -1) return full
+
+ const title = extractTitleAttr(panelAttrs)
+ if (!title) return full
+
+ const description = body
+ .slice(i + 1, closeIdx)
+ .replace(/<[^>]+>/g, ' ')
+ .replace(/\s+/g, ' ')
+ .trim()
- return objs
- .map((o) => {
- const title = o.match(/title:\s*['"`]([^'"`]+)['"`]/)?.[1]
- const href = o.match(/href:\s*['"`]([^'"`]+)['"`]/)?.[1]
- const desc = o.match(/description:\s*[`'"]([^`'"]+)[`'"]/)?.[1]
- return title && href ? `- [${title}](${href})${desc ? `. ${desc}` : ''}` : ''
- })
- .filter(Boolean)
- .join('\n')
+ return `- [${title}](${href})${description ? `. ${description}` : ''}`
})
}
@@ -165,11 +210,8 @@ async function generate() {
const withPartials = await inlinePartials(rawContent)
const withSteps = convertStepHike(withPartials)
- const withLists =
- filePath === 'content/guides/getting-started.mdx'
- ? convertResourceLists(withSteps)
- : withSteps
- const processed = stripJsxTags(withLists)
+ const withLinks = convertLinkPanels(withSteps)
+ const processed = stripJsxTags(withLinks)
const header = [
data.title ? `# ${data.title}` : '',
diff --git a/apps/docs/lib/guidesData.ts b/apps/docs/lib/guidesData.ts
deleted file mode 100644
index 2bf5c7ccc37db..0000000000000
--- a/apps/docs/lib/guidesData.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * Data used in guide MDX files.
- *
- * This data is passed to MDX files via scope to avoid using `export const`
- * within MDX content, which is not supported by next-mdx-remote.
- *
- * @see https://github.com/hashicorp/next-mdx-remote#import--export
- */
-
-export const guidesData = {
- // apps/docs/content/guides/self-hosting.mdx
- selfHostingCommunity: [
- {
- name: 'Kubernetes',
- description: 'Helm charts to deploy a Supabase on Kubernetes.',
- href: 'https://github.com/supabase-community/supabase-kubernetes',
- },
- {
- name: 'Traefik',
- description: 'A self-hosted Supabase setup with Traefik as a reverse proxy.',
- href: 'https://github.com/supabase-community/supabase-traefik',
- },
- ],
-
- // apps/docs/content/guides/ai.mdx
- aiExamples: [
- {
- name: 'Headless Vector Search',
- description:
- 'A toolkit to perform vector similarity search on your knowledge base embeddings.',
- href: '/guides/ai/examples/headless-vector-search',
- },
- {
- name: 'Image Search with OpenAI CLIP',
- description: 'Implement image search with the OpenAI CLIP Model and Supabase Vector.',
- href: '/guides/ai/examples/image-search-openai-clip',
- },
- {
- name: 'Hugging Face inference',
- description: 'Generate image captions using Hugging Face.',
- href: '/guides/ai/examples/huggingface-image-captioning',
- },
- {
- name: 'OpenAI completions',
- description: 'Generate GPT text completions using OpenAI in Edge Functions.',
- href: '/guides/ai/examples/openai',
- },
- {
- name: 'Building ChatGPT Plugins',
- description: 'Use Supabase as a Retrieval Store for your ChatGPT plugin.',
- href: '/guides/ai/examples/building-chatgpt-plugins',
- },
- {
- name: 'Vector search with Next.js and OpenAI',
- description:
- 'Learn how to build a ChatGPT-style doc search powered by Next.js, OpenAI, and Supabase.',
- href: '/guides/ai/examples/nextjs-vector-search',
- },
- ],
-
- aiIntegrations: [
- {
- name: 'OpenAI',
- description:
- 'OpenAI is an AI research and deployment company. Supabase provides a simple way to use OpenAI in your applications.',
- href: '/guides/ai/examples/building-chatgpt-plugins',
- },
- {
- name: 'Amazon Bedrock',
- description:
- 'A fully managed service that offers a choice of high-performing foundation models from leading AI companies.',
- href: '/guides/ai/integrations/amazon-bedrock',
- },
- {
- name: 'Hugging Face',
- description:
- "Hugging Face is an open-source provider of NLP technologies. Supabase provides a simple way to use Hugging Face's models in your applications.",
- href: '/guides/ai/hugging-face',
- },
- {
- name: 'LangChain',
- description:
- 'LangChain is a language-agnostic, open-source, and self-hosted API for text translation, summarization, and sentiment analysis.',
- href: '/guides/ai/langchain',
- },
- {
- name: 'LlamaIndex',
- description: 'LlamaIndex is a data framework for your LLM applications.',
- href: '/guides/ai/integrations/llamaindex',
- },
- ],
-
- // apps/docs/content/guides/storage.mdx
- storageExamples: [
- {
- name: 'Resumable Uploads with Uppy',
- description:
- 'Use Uppy to upload files to Supabase Storage using the TUS protocol (resumable uploads).',
- href: 'https://github.com/supabase/supabase/tree/master/examples/storage/resumable-upload-uppy',
- },
- ],
-}
diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs
index bfeb5206c222e..9243af773b278 100644
--- a/apps/docs/next.config.mjs
+++ b/apps/docs/next.config.mjs
@@ -171,20 +171,6 @@ const nextConfig = {
source: '/guides/database/replication/replication-faq',
destination: '/guides/database/replication/external-replication-faq',
permanent: true,
- },
- // Reference pages use hash anchors for sections; redirect the legacy
- // path-style /reference//introduction (and versioned variants)
- // back to the base reference URL. Order matters: introduction first so
- // it strips to a bare URL, then the section rules add a hash anchor.
- {
- source: '/reference/:lib/:version(v\\d+)/:section',
- destination: '/reference/:lib/:version#:section',
- permanent: true,
- },
- {
- source: '/reference/:lib/:section((?!v\\d+$)[^/]+)',
- destination: '/reference/:lib#:section',
- permanent: true,
},
]
},
diff --git a/apps/docs/resources/guide/guideModelLoader.ts b/apps/docs/resources/guide/guideModelLoader.ts
index 5af209f9f3824..551bd98abfeaa 100644
--- a/apps/docs/resources/guide/guideModelLoader.ts
+++ b/apps/docs/resources/guide/guideModelLoader.ts
@@ -140,9 +140,9 @@ export class GuideModelLoader {
},
(error) => {
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
- return new FileNotFoundError('', error)
+ throw new FileNotFoundError('', error)
}
- return new Error(
+ throw new Error(
`Failed to load guide from ${relPath}: ${extractMessageFromAnyError(error)}`,
{
cause: error,
diff --git a/apps/studio/components/interfaces/App/AppBannerWrapper.tsx b/apps/studio/components/interfaces/App/AppBannerWrapper.tsx
index b4a45644668ac..54026ead90bca 100644
--- a/apps/studio/components/interfaces/App/AppBannerWrapper.tsx
+++ b/apps/studio/components/interfaces/App/AppBannerWrapper.tsx
@@ -3,7 +3,6 @@ import { PropsWithChildren, useEffect } from 'react'
import { OrganizationResourceBanner } from '../Organization/HeaderBanner'
import { ClockSkewBanner } from '@/components/layouts/AppLayout/ClockSkewBanner'
-import { FlyDeprecationBanner } from '@/components/layouts/AppLayout/FlyDeprecationBanner'
import { NoticeBanner } from '@/components/layouts/AppLayout/NoticeBanner'
import { StatusPageBanner } from '@/components/layouts/AppLayout/StatusPageBanner'
import { BannerTOSUpdate } from '@/components/ui/BannerStack/Banners/BannerTOSUpdate'
@@ -43,7 +42,6 @@ export const AppBannerWrapper = ({ children }: PropsWithChildren<{}>) => {
{showNoticeBanner && }
-
{clockSkewBanner && }
diff --git a/apps/studio/components/interfaces/ErrorHandling/ErrorMatcher.tsx b/apps/studio/components/interfaces/ErrorHandling/ErrorMatcher.tsx
index 1542c9658e138..a094881fb6231 100644
--- a/apps/studio/components/interfaces/ErrorHandling/ErrorMatcher.tsx
+++ b/apps/studio/components/interfaces/ErrorHandling/ErrorMatcher.tsx
@@ -26,11 +26,13 @@ export function ErrorMatcher({ title, error, supportFormParams, className }: Err
supportFormParams={supportFormParams}
className={className}
onRender={() => {
- track('dashboard_error_created', {
- source: 'error_display',
- errorType: mapping?.id,
- hasTroubleshooting: !!mapping,
- })
+ if (Math.random() < 0.1) {
+ track('dashboard_error_created', {
+ source: 'error_display',
+ errorType: mapping?.id,
+ hasTroubleshooting: !!mapping,
+ })
+ }
if (mapping) {
track('inline_error_troubleshooter_exposed', { errorType: mapping.id })
}
diff --git a/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/MarkdownContent.tsx b/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/MarkdownContent.tsx
index 6daf72b1047df..a4d46551f1ab3 100644
--- a/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/MarkdownContent.tsx
+++ b/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/MarkdownContent.tsx
@@ -1,6 +1,5 @@
import { useEffect, useState } from 'react'
-
-import { Markdown } from '@/components/interfaces/Markdown'
+import { Markdown } from 'ui-patterns/Markdown'
interface MarkdownContentProps {
content: string | null | undefined
@@ -34,5 +33,5 @@ export const MarkdownContent = ({
const content = remoteContent || localContent
- return {content}
+ return {content}
}
diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/UpgradeWarnings.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/UpgradeWarnings.tsx
index ba02bf5116f46..a38bb8efd8483 100644
--- a/apps/studio/components/interfaces/Settings/Infrastructure/UpgradeWarnings.tsx
+++ b/apps/studio/components/interfaces/Settings/Infrastructure/UpgradeWarnings.tsx
@@ -46,6 +46,10 @@ const getValidationErrorTitle = (error: ProjectUpgradeEligibilityValidationError
return `${error.schema_name}.${error.obj_name}`
case 'active_replication_slot':
return error.slot_name
+ case 'project_hibernating':
+ return 'Project is hibernating'
+ case 'x86_architecture':
+ return 'Project is running on x86 architecture'
}
}
@@ -67,6 +71,10 @@ const getValidationErrorDescription = (error: ProjectUpgradeEligibilityValidatio
return `Move the ${error.obj_type} to your own schema`
case 'active_replication_slot':
return 'Drop the active replication slot'
+ case 'project_hibernating':
+ return 'The project is currently hibernating and will wake on next supported request'
+ case 'x86_architecture':
+ return 'The project is running on x86 architecture and cannot be upgraded'
}
}
diff --git a/apps/studio/components/interfaces/Storage/StorageMenuV2.tsx b/apps/studio/components/interfaces/Storage/StorageMenuV2.tsx
index 9ea0cbe55e55d..65d3746b816d3 100644
--- a/apps/studio/components/interfaces/Storage/StorageMenuV2.tsx
+++ b/apps/studio/components/interfaces/Storage/StorageMenuV2.tsx
@@ -1,4 +1,4 @@
-import { IS_PLATFORM, useParams } from 'common'
+import { useParams } from 'common'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { Badge, Menu } from 'ui'
@@ -10,6 +10,7 @@ import {
useIsAnalyticsBucketsEnabled,
useIsVectorBucketsEnabled,
} from '@/data/config/project-storage-config-query'
+import { useDeploymentMode } from '@/hooks/misc/useDeploymentMode'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
import { SHORTCUT_IDS, type ShortcutId } from '@/state/shortcuts/registry'
import { useShortcut } from '@/state/shortcuts/useShortcut'
@@ -25,6 +26,8 @@ export const StorageMenuV2 = () => {
const { ref } = useParams()
const page = useStorageV2Page()
+ const { isCli, isPlatform } = useDeploymentMode()
+
const { storageAnalytics, storageVectors } = useIsFeatureEnabled([
'storage:analytics',
'storage:vectors',
@@ -33,8 +36,8 @@ export const StorageMenuV2 = () => {
const isAnalyticsBucketsEnabled = useIsAnalyticsBucketsEnabled({ projectRef: ref })
const isVectorBucketsEnabled = useIsVectorBucketsEnabled({ projectRef: ref })
- const showAnalytics = IS_PLATFORM && storageAnalytics
- const showVectors = IS_PLATFORM && storageVectors
+ const showAnalytics = isPlatform && storageAnalytics
+ const showVectors = (isPlatform && storageVectors) || isCli
useShortcut(SHORTCUT_IDS.NAV_STORAGE_FILES, () => router.push(`/project/${ref}/storage/files`))
useShortcut(
@@ -48,7 +51,7 @@ export const StorageMenuV2 = () => {
{ enabled: showVectors }
)
useShortcut(SHORTCUT_IDS.NAV_STORAGE_S3, () => router.push(`/project/${ref}/storage/s3`), {
- enabled: IS_PLATFORM,
+ enabled: isPlatform,
})
const bucketTypes = Object.entries(BUCKET_TYPES).filter(([key]) => {
@@ -95,7 +98,7 @@ export const StorageMenuV2 = () => {
})}
- {IS_PLATFORM && (
+ {isPlatform && (
<>
diff --git a/apps/studio/components/interfaces/Storage/VectorBuckets/CreateVectorBucketDialog.tsx b/apps/studio/components/interfaces/Storage/VectorBuckets/CreateVectorBucketDialog.tsx
index c3099f00e319a..fb0f8c40c4260 100644
--- a/apps/studio/components/interfaces/Storage/VectorBuckets/CreateVectorBucketDialog.tsx
+++ b/apps/studio/components/interfaces/Storage/VectorBuckets/CreateVectorBucketDialog.tsx
@@ -141,15 +141,22 @@ export const CreateVectorBucketDialog = ({
}
await createS3VectorsWrapper({ bucketName: values.name })
+ toast.success(`Successfully created vector bucket ${values.name}`)
} catch (error: any) {
- toast.warning(
- `Failed to create vector bucket integration: ${error.message}. The bucket will be created but you will need to manually install the integration.`
+ toast.success(
+
+
Successfully created vector bucket {values.name}
+
+ However, bucket integration will need to be manually installed as we ran into an error:
+
+
{error.message}
+
,
+ { duration: 8000 }
)
}
- setIsLoading(false)
+ setIsLoading(false)
track('storage_bucket_created', { bucketType: 'vector' })
- toast.success(`Successfully created vector bucket ${values.name}`)
form.reset()
setVisible(false)
}
diff --git a/apps/studio/components/interfaces/Storage/VectorBuckets/CreateVectorTableSheet.tsx b/apps/studio/components/interfaces/Storage/VectorBuckets/CreateVectorTableSheet.tsx
index af0a1b2e2063b..a8ff4e49bd92e 100644
--- a/apps/studio/components/interfaces/Storage/VectorBuckets/CreateVectorTableSheet.tsx
+++ b/apps/studio/components/interfaces/Storage/VectorBuckets/CreateVectorTableSheet.tsx
@@ -34,6 +34,7 @@ import { DocsButton } from '@/components/ui/DocsButton'
import { useFDWImportForeignSchemaMutation } from '@/data/fdw/fdw-import-foreign-schema-mutation'
import { useVectorBucketIndexCreateMutation } from '@/data/storage/vector-bucket-index-create-mutation'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
+import { useDeploymentMode } from '@/hooks/misc/useDeploymentMode'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { DOCS_URL } from '@/lib/constants'
@@ -104,6 +105,7 @@ interface CreateVectorTableSheetProps {
export const CreateVectorTableSheet = ({ bucketName }: CreateVectorTableSheetProps) => {
const { data: project } = useSelectedProjectQuery()
+ const { isCli } = useDeploymentMode()
const [visible, setVisible] = useQueryState(
'newTable',
@@ -117,7 +119,8 @@ export const CreateVectorTableSheet = ({ bucketName }: CreateVectorTableSheetPro
?.split('supabase_target_schema=')[1]
// [Joshen] Can remove this once this restriction is removed
- const showIndexCreationNotice = isStagingLocal && !!project && project?.region !== 'us-east-1'
+ const showIndexCreationNotice =
+ isStagingLocal && !isCli && !!project && project?.region !== 'us-east-1'
const defaultValues = {
name: '',
diff --git a/apps/studio/components/interfaces/Storage/VectorBuckets/VectorBucketsErrorState.test.tsx b/apps/studio/components/interfaces/Storage/VectorBuckets/VectorBucketsErrorState.test.tsx
new file mode 100644
index 0000000000000..296c90edbfd1e
--- /dev/null
+++ b/apps/studio/components/interfaces/Storage/VectorBuckets/VectorBucketsErrorState.test.tsx
@@ -0,0 +1,52 @@
+import { screen } from '@testing-library/react'
+import { beforeEach, describe, expect, test, vi } from 'vitest'
+
+import { VectorBucketsErrorState } from './VectorBucketsErrorState'
+import type { DeploymentMode } from '@/hooks/misc/useDeploymentMode'
+import { customRender } from '@/tests/lib/custom-render'
+import { ResponseError } from '@/types'
+
+const { mockUseDeploymentMode } = vi.hoisted(() => ({
+ mockUseDeploymentMode: vi.fn<() => DeploymentMode>(),
+}))
+
+vi.mock('@/hooks/misc/useDeploymentMode', () => ({
+ useDeploymentMode: mockUseDeploymentMode,
+}))
+
+vi.mock('@/lib/telemetry/track', () => ({
+ useTrack: () => vi.fn(),
+}))
+
+const deploymentMode = (overrides: Partial): DeploymentMode => ({
+ isPlatform: false,
+ isCli: false,
+ isSelfHosted: false,
+ ...overrides,
+})
+
+describe('VectorBucketsErrorState', () => {
+ beforeEach(() => {
+ mockUseDeploymentMode.mockReset()
+ })
+
+ test('CLI: shows the config.toml enable guidance, not the support error', () => {
+ mockUseDeploymentMode.mockReturnValue(deploymentMode({ isCli: true }))
+
+ customRender()
+
+ expect(screen.getByText('Vector buckets are not enabled')).toBeInTheDocument()
+ expect(screen.getByText('supabase/config.toml')).toBeInTheDocument()
+ expect(screen.queryByText('Contact support')).not.toBeInTheDocument()
+ })
+
+ test('platform: shows the generic support error', () => {
+ mockUseDeploymentMode.mockReturnValue(deploymentMode({ isPlatform: true }))
+
+ customRender()
+
+ expect(screen.getByText('Failed to retrieve vector buckets')).toBeInTheDocument()
+ expect(screen.getByText('Contact support')).toBeInTheDocument()
+ expect(screen.queryByText('Vector buckets are not enabled')).not.toBeInTheDocument()
+ })
+})
diff --git a/apps/studio/components/interfaces/Storage/VectorBuckets/VectorBucketsErrorState.tsx b/apps/studio/components/interfaces/Storage/VectorBuckets/VectorBucketsErrorState.tsx
new file mode 100644
index 0000000000000..6bd95e679e30d
--- /dev/null
+++ b/apps/studio/components/interfaces/Storage/VectorBuckets/VectorBucketsErrorState.tsx
@@ -0,0 +1,16 @@
+import { VectorBucketsLocalDisabledState } from './VectorBucketsLocalDisabledState'
+import AlertError from '@/components/ui/AlertError'
+import { useDeploymentMode } from '@/hooks/misc/useDeploymentMode'
+import type { ResponseError } from '@/types'
+
+interface VectorBucketsErrorStateProps {
+ error: ResponseError | null
+}
+
+export const VectorBucketsErrorState = ({ error }: VectorBucketsErrorStateProps) => {
+ const { isCli } = useDeploymentMode()
+
+ if (isCli) return
+
+ return
+}
diff --git a/apps/studio/components/interfaces/Storage/VectorBuckets/VectorBucketsLocalDisabledState.tsx b/apps/studio/components/interfaces/Storage/VectorBuckets/VectorBucketsLocalDisabledState.tsx
new file mode 100644
index 0000000000000..b58bd8fd8fb14
--- /dev/null
+++ b/apps/studio/components/interfaces/Storage/VectorBuckets/VectorBucketsLocalDisabledState.tsx
@@ -0,0 +1,28 @@
+import { Admonition } from 'ui-patterns/admonition'
+import { CodeBlock } from 'ui-patterns/CodeBlock'
+
+const CONFIG_SNIPPET = `[storage.vector]
+enabled = true
+max_buckets = 10
+max_indexes = 5`
+
+/**
+ * Shown on the local CLI when listing vector buckets fails — most commonly
+ * because `[storage.vector]` is not enabled in `config.toml`. Studio can't read
+ * `config.toml` directly, so we surface the snippet to enable the feature rather
+ * than the generic "contact support" error.
+ */
+export const VectorBucketsLocalDisabledState = () => {
+ return (
+
+
+ To use vector buckets locally, enable them in your{' '}
+ supabase/config.toml and restart with{' '}
+ supabase start.
+