## Context
Resolves https://github.com/supabase/supabase/issues/43548
There's currently an issue with the Table Editor where if you have, for
example, a nullable `text` column with a default value, inserting a new
row and selecting "Set to NULL" doesn't do anything, and saving will
insert the row with the default value
<img width="700" height="258" alt="image"
src="https://github.com/user-attachments/assets/6a284ebb-c346-40a6-9a30-793118844084"
/>
This stems from a legacy logic in the Table Editor whereby we treat
`null` values as "no input" - which is incorrect as `null` values are
also valid values. So the PR here changes a few things to resolve this
properly:
## Changes involved
Main fix:
- `undefined` will be the "no input" value instead, and it'll be the
default value when generating the row object for inserting a new row
- `NULL` or even empty string like `''` will be treated as they are
(valid inputs)
Secondary adjustments:
- (Queue operations) Queueing an insert with no value but default value
is NULL, will show the placeholder as `DEFAULT` instead of `NULL` for
better accuracy in representation
<img width="892" height="96" alt="image"
src="https://github.com/user-attachments/assets/02cf86bf-c17b-4e25-9a8f-17960b1d2575"
/>
- Added a `Set to Default` CTA here, but will only show up if adding a
new row or updating a queued insert row operation, which will set the
value of the input field back to `undefined` for PG to handle it as the
default value
<img width="734" height="208" alt="image"
src="https://github.com/user-attachments/assets/23887c0c-533e-4494-acbe-61309ff5d7c5"
/>
## To test
Verify within the Table Editor (along with queue operation feature
preview)
- For inserting a new row, setting value to NULL and setting value to
Default works
- For updating a row, setting value to NULL works
Migrates all studio-related Cursor rules to Claude skills and adds a
top-level `.claude/CLAUDE.md` for project context. Docs rules left in
place.
**Decisions:**
- Only studio + testing rules migrated — docs rules intentionally left
in `.cursor/rules/docs/`
- Vitest skill already shared via symlink (`.claude/skills/vitest` →
`.agents/skills/vitest`) — nothing to migrate
- Grouped ~21 granular cursor rules into 5 new skills + 1 updated skill
by topic
- `studio-architecture` skill fully merged into `CLAUDE.md` and deleted
to avoid overlap
- Skills are self-contained (content inlined, not relying on sub-files)
since Claude reads SKILL.md first
- Skills cross-reference each other inline where relevant (e.g.
best-practices → testing, error-handling, queries)
- No `paths` frontmatter — would auto-inject full skill content on every
matching file. Current description-based matching is more selective and
token-efficient.
**Removed:**
- `.cursor/rules/studio/` (21 rule files covering architecture, best
practices, UI patterns, queries, styling, etc.)
- `.cursor/rules/testing/` (e2e-studio + unit-integration rules)
- `.cursor/rules/studio-useStaticEffectEvent.mdc`
- `.claude/skills/studio-architecture/` — fully merged into CLAUDE.md to
avoid duplication
- `.claude/skills/studio-testing/rules/` — orphaned sub-files after
inlining content into SKILL.md
**Added:**
- `.claude/CLAUDE.md` — concise monorepo overview with structure,
commands, and conventions. Absorbs studio-architecture content.
References `studio-*` skills for detail.
- `.claude/skills/studio-best-practices/` — boolean naming, component
structure, loading/error/success patterns, state management, hooks,
TypeScript conventions. Cross-references `vercel-composition-patterns`,
`studio-ui-patterns`, `studio-queries`, `studio-error-handling`, and
`studio-testing` inline where relevant.
- `.claude/skills/studio-ui-patterns/` — layout, forms, tables, charts,
empty states, navigation, cards, alerts, sheets. Grouped from ~10
separate cursor rules into one cohesive skill.
- `.claude/skills/studio-queries/` — React Query `queryOptions` pattern,
`keys.ts` structure, mutation hook template, imperative fetching.
- `.claude/skills/use-static-effect-event/` — the `useStaticEffectEvent`
hook: when to use, when not to, patterns, implementation.
**Changed:**
- `.claude/skills/studio-e2e-tests/` — renamed from `e2e-studio-tests`
for `studio-*` naming consistency. Merged race condition, waiting
strategy, test structure, assertion, and cleanup patterns from the
cursor e2e rule.
- `.claude/skills/studio-testing/` — inlined key content from sub-rule
files directly into SKILL.md so it's self-contained. Removed broken
`AGENTS.md` reference. Deleted orphaned `rules/` sub-files.
- `.claude/skills/vercel-composition-patterns/` — added note that Studio
uses React 18, so React 19 patterns should be skipped.
- `.gitignore` — added `!.claude/CLAUDE.md` exception so it's tracked.
## To test
- Open Claude Code in the repo, verify `.claude/CLAUDE.md` loads as
project context
- Ask Claude about Studio conventions and verify it references the right
skills
- Check that `studio-*` skills appear in the skill list
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR updates @supabase/*-js libraries to version 2.100.1.
**Source**: supabase-js-stable-release
**Changes**:
- Updated @supabase/supabase-js to 2.100.1
- Updated @supabase/auth-js to 2.100.1
- Updated @supabase/realtime-js to 2.100.1
- Updated @supabase/postgest-js to 2.100.1
- Refreshed pnpm-lock.yaml
This PR was created automatically.
Edit by @mandarini:
Fix type error in `lib/events.ts` caused by `supabase-js` `v2.100.1`
adding strict column name validation to `.eq()`. Updated the `meetups`
table definition in `database.types.ts` to include missing columns
(`is_published`, `country`, `start_at`, `launch_week`).
---------
Co-authored-by: supabase-workflow-trigger[bot] <266661614+supabase-workflow-trigger[bot]@users.noreply.github.com>
Co-authored-by: Katerina Skroumpelou <sk.katherine@gmail.com>
## What
Updates all `setAll` cookie handler implementations across docs and
examples to accept the new `headers` second argument introduced in
`@supabase/ssr` v0.10.0
([supabase/ssr#176](https://github.com/supabase/ssr/pull/176)).
## Why
`@supabase/ssr` v0.10.0 introduced a breaking change: `setAll` now
receives a required second argument `headers: Record<string, string>`
alongside the cookies array. When a token refresh occurs, the library
passes cache headers (`Cache-Control`, `Expires`, `Pragma`) that must be
applied to the HTTP response to prevent CDN caching of auth responses.
Because TypeScript allows functions with fewer parameters to satisfy a
type expecting more, existing `setAll` implementations do not produce a
type error when the second argument is omitted. Users who copy an
outdated snippet will silently miss the CDN protection.
Root cause and context:
[supabase/supabase-js#1682](https://github.com/supabase/supabase-js/issues/1682)
## Changes
**Proxy/middleware contexts** (where token refreshes happen) now apply
the cache headers to their response:
- Next.js proxy files: `supabaseResponse.headers.set(key, value)`
- SvelteKit hooks: `event.setHeaders(headers)`
- Hono middleware: `c.header(key, value)`
- Pages Router (Express-style): `ctx.res.setHeader(key, value)`
- Remix/React Router loaders and actions: applied to response headers
(outer `headers` variable renamed to `responseHeaders` to avoid naming
conflict with the new param)
**Server Component and API route contexts** (no response object
available) accept `_headers` without applying them.
## Files updated
- `apps/docs/content/guides/auth/server-side/creating-a-client.mdx`
(inline Astro, Remix, React Router, Express snippets)
- `apps/docs/content/_partials/oauth_pkce_flow.mdx`
- `apps/docs/content/guides/auth/oauth-server/getting-started.mdx`
- `apps/docs/content/guides/auth/passwords.mdx`
-
`apps/docs/content/troubleshooting/how-to-migrate-from-supabase-auth-helpers-to-ssr-package-5NRunM.mdx`
- `examples/auth/nextjs/`, `examples/auth/nextjs-full/` (proxy + server)
- `examples/auth/sveltekit/`, `examples/auth/sveltekit-full/`
- `examples/auth/hono/`, `examples/auth/hono-full/`
- `examples/user-management/nextjs-user-management/` (proxy + server)
- `examples/user-management/sveltekit-user-management/`
- `examples/realtime/nextjs-authorization-demo/` (proxy + server)
- `examples/realtime/nextjs-auth-presence/` (pages router)
- `examples/prompts/nextjs-supabase-auth.md`
## Summary
The `connectSection` A/B experiment concluded as a true null (no effect
on activation or any downstream metric after 13 days at 50/50, ~153K
mature orgs). Saxon decided to ship the Connect section as the permanent
experience. This PR removes the Getting Started control variant, the old
Connect modal, all experiment flag gating, and related telemetry types.
## Changes
- Delete `GettingStarted/` directory (5 files: section component, types,
utils, progress hook)
- Delete old `Connect.tsx` dialog modal (replaced by ConnectSheet)
- Remove `connectSection` PostHog flag reads from `Home.tsx` and
`LayoutHeader.tsx`
- Remove `getSectionVisibility()` experiment logic and
`ConnectSectionVariant` type
- Remove `getting-started` from `DEFAULT_SECTION_ORDER`
- Always render `<ConnectSheet />` in header (no more conditional with
old `<Connect />` modal)
- Remove `variant` prop from `ConnectSection` component
- Remove 4 getting-started telemetry event interfaces from
`telemetry-constants.ts`
- Update `mergeSectionOrder` tests to reflect new section order
## Testing
Tested on Vercel preview:
- [x] Project homepage shows Connect section for new projects (< 10 days
old)
- [x] Connect section hidden for mature projects (> 10 days old)
- [x] Header Connect button opens ConnectSheet (not old modal)
- [x] Connect tiles open ConnectSheet with correct tab
- [x] Section drag-and-drop still works without getting-started in the
order
- [x] Existing users with `getting-started` in localStorage order don't
break (mergeSectionOrder strips it)
## Linear
- fixes GROWTH-730
---------
Co-authored-by: Alaister Young <alaister@users.noreply.github.com>
Previously, the POST to `/v1/projects/{ref}/branches` didn't work on
free projects, which left some Supabase projects setup without a default
branch. Easy fix for those projects would be to disable/enable the whole
integration.
This PR fixes that so that when the user wants to setup a production
sync, the code checks if there's branches already setup and if not, sets
the selected branch as default.
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
## Context
Related to marketplace integrations
Shifts Database Webhooks integration to the new Integrations UI. This
one's a bit different from the previous PRs as this involves a full SQL
installation query instead of only just a database extension. So am
tweaking `Integrations.constants` a little.
For context eventually all the integrations will be pulled remotely from
a database, so am still trying to figure out an optimal data structure,
but requirements will be clearer as we build out the UI
RE installing integrations:
- For now, if the integration has a provided SQL installation command,
that'll take precedence
- Else, if the integration has a provided SQL installation query, we'll
use that on the /query endpoint
- Otherwise, if the integration only requires database extensions,
dashboard will generate the queries to install the extensions
- In the case of the former tho, we won't allow users to choose which
schema to install the extension in too
Just ping me if any clarification's required!
## To test
- [ ] Verify that you can install the database webhooks with the new
integration UI
- [ ] Verify that behaviour is status quo without the new integration UI
## What kind of change does this PR introduce?
Component update.
## What is the current behaviour?
TanStack tables in the repo are split between the shared `TableHeadSort`
primitive and the older Studio-local `DataTableColumnHeader` helper,
which makes the sorting UI and integration path inconsistent.
If you were to just use `DataTableColumnHeader` in `ui-patterns/Table`,
you’d get a very different visual result to the `TableHeadSort` UI you
see in most other tables.
## What is the new behaviour?
Adds a shared `TanStackTableHeadSort` adapter in `ui-patterns/Table`,
backed by the existing `TableHeadSort` primitive, and switches the
webhook table plus the design-system TanStack demo to that canonical
path. `DataTableColumnHeader` stays as a deprecated wrapper for now,
Studio gets a lint guard to block new imports of it, and the table docs
now point TanStack tables at the shared adapter explicitly.
## To test
Check out column sorting on the Platform Webhook endpoint deliveries
table.
This PR moves several components which rely on `next` out of the `ui`
package to the `ui-patterns` package.
`ui-patterns` package is intented to be imported with specific imports
so it's ok if there are components reliant on `next` in there.
The `SonnerToaster` component has removed its dependency by requiring a
prop for `theme`.
## Context
Just brings more integrations over to the new UI bit by bit
- Vault
- Cron
- Data API
- GraphiQL
Will be tackling webhooks next which is a bit different as its not just
a database extension
## Context
Related to marketplace related work, just moves the Queues integration
to the new UI (Changes are feature flagged)
<img width="1145" height="584" alt="image"
src="https://github.com/user-attachments/assets/d3245889-597d-44e2-9850-f20907e42056"
/>
Installation is now in a side panel with the intention that it'll just
be a single click to install integrations that involve multiple parts
<img width="400" height="955" alt="image"
src="https://github.com/user-attachments/assets/71903b61-6bd2-486c-903e-b48ae2133887"
/>
## To test
- Verify that you can install the integration and everything else should
be status quo
- Verify that everything should be status quo if the flag is off
## What kind of change does this PR introduce?
UI update that resolves DEPR-114. Also resolves DEPR-113.
## What is the current behavior?
- The breadcrumbs on the file explorer have some rough edges in column
view
- Fancy hide/show behavior
- Hidden tap targets
- `FileExplorerHeader` actions can overflow on the x-axis
- The Navigate button is only shown on hover
- The inline Navigate flow does not work well on smaller screens
## What is the new behavior?
- Column view now shows the same in-explorer breadcrumb trail as list
view
- The active breadcrumb is visually emphasized, while inactive
breadcrumbs remain clickable
- The back affordance now uses a clearer arrow treatment with a stronger
separator from the breadcrumb trail
- The Navigate button is permanently visible and moved to the right-side
action group before Reload
- Navigate now opens a dialog on both desktop and mobile
- Added typed telemetry so we can measure `Navigate` usage before
deciding whether to keep or remove it
- Fixed header overflow by letting the full header contents scroll
horizontally together instead of visibly spilling out
| Before | After |
| --- | --- |
| <img width="947" height="997" alt="Buckets Storage AWS Healthy
Toolshed Supabase"
src="https://github.com/user-attachments/assets/fa53fdd4-954c-4832-bf9b-210b63ae020b"
/> | <img width="947" height="997" alt="Buckets Storage AWS Healthy
Toolshed Supabase"
src="https://github.com/user-attachments/assets/3689a0e5-97d1-4b36-a2dd-7adce23add5d"
/> |
| <img width="864" height="997" alt="Buckets Storage AWS Healthy
Toolshed Supabase"
src="https://github.com/user-attachments/assets/ad559118-205f-40e2-b3c5-97cef462d5f5"
/> | <img width="864" height="997" alt="Buckets Storage AWS Healthy
Toolshed Supabase"
src="https://github.com/user-attachments/assets/9c569b29-7c58-4a33-b809-34d6ed919008"
/> |
## Additional context
Also added a link to the `Buckets` portion of the `PageHeader`
breadcrumb:
```text
Files > Buckets > MyBucketName
```
It goes to the same place as Files because the root Files page lists
buckets, but having both links there feels more ergonomic in practice.
---------
Co-authored-by: Ali Waseem <waseema393@gmail.com>
## Problem
Follow-up to #44252. The previous fix handled the case where the user
waits on the page after accepting (GTM writes `ucData`), but there's a
second scenario: if the user accepts and navigates to another app
quickly (before GTM finishes), `ucData` hasn't been written yet. The SDK
on the new app overwrites `uc_user_interaction: "true"` with `"false"`
and shows the banner again.
## What changed
`hasPreviousConsentInUcData` is now `detectPriorConsent` and checks two
signals before `UC.init()` overwrites them:
1. **Slow navigation** (existing): `ucData` contains all services with
`consent: true`
2. **Fast navigation** (new): `uc_user_interaction` is `"true"` — the
SDK on the previous app wrote this but GTM hasn't had time to replace it
yet
Also adds unit tests covering both scenarios, edge cases (empty
services, malformed JSON, mixed signals), and the combined behavior.
## Testing
- 13 unit tests for `detectPriorConsent()` covering all localStorage
state combinations
- Can't fully reproduce on staging previews (CSP blocks GTM), verified
root cause via production console monitoring
Closes FE-2648
## Problem
When scrolling down in a column that has more than 200 items to trigger
its lazy loading, while other columns are displayed and the targeted
column isn't the last one, it doesn't load its items.
Fixes#43799
## Solution
- Don't rely on the storage state for opened folders for the lazy
loading
- Add the item path information to the column and use it to define the
API request path
## How to test
- create a bucket
- create a folder and upload more than 200 items in it
- in this folder, create a sub folder and upload more than 200 items in
it (make sure its name position it _before_ the files)
- refresh the page
- without scrolling the first column, select the subfolder
- now scroll down on the first column past the last of its items and
verify it loads more items
- do the same on the sub folder column
To easily create many files to upload, use the following commands:
For root folder:
```sh
for i in {0..300}
do
echo hello >"root_$(printf "%03d" "$i").txt"
done
```
For sub folder:
```sh
for i in {0..300}
do
echo hello >"sub_$(printf "%03d" "$i").txt"
done
```
Include release notes in the automated PR that updates supabase-js
across the repo.
* Looks at what version is installed
* It includes all changelogs between installed version and
to-be-installed version
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Removes the control variant and replaces it with the test variant as
winner.
## What is the current behavior?
-
## What is the new behavior?
-
## Additional context
Add any other context or screenshots.
## Problem
After PR #43221 gated `TelemetryTagManager` behind consent, the EU
cookie consent banner started reappearing on every page load and when
navigating between apps (www, studio, docs).
Back in late February we changed `TelemetryTagManager` to only load when
the user has accepted consent. This was the right call for GDPR — don't
load tracking scripts before consent. But it created a chicken-and-egg
problem with how the Usercentrics SDK stores consent.
## What happened
When a user clicks Accept, the SDK writes `uc_settings` +
`uc_user_interaction: true` to localStorage. Then the GTM script loads
(now that consent is granted), and its Usercentrics integration
immediately replaces those keys with a compressed `ucString` + `ucData`
format — deleting the originals.
On the next page load, `UC.init()` only knows how to read `uc_settings`.
It can't find it (GTM deleted it), so it treats the user as brand new
and shows the banner again. Before #43221, GTM loaded on every page
unconditionally, so its integration was already present during
`UC.init()` and could interpret the compressed format.
Confirmed via production console monitoring — the exact sequence after
clicking Accept:
```
setItem("uc_settings", ...) // SDK writes consent
setItem("uc_user_interaction", "true") // SDK marks interaction
removeItem("uc_settings") // GTM deletes SDK format
removeItem("uc_user_interaction") // GTM deletes SDK format
setItem("ucString", ...) // GTM writes compressed format
setItem("ucData", ...) // GTM writes compressed format
```
## Changes
- Read `ucData` from localStorage **before** `UC.init()` to detect prior
consent in the compressed format
- If the SDK wants to show the banner but `ucData` shows all services
were previously accepted, silently re-accept instead of re-prompting
- Added try/catch around the SDK initialization (was fire-and-forget
with no error handling, any failure was completely silent)
- Error fallback also honors prior `ucData` consent if the SDK fails to
initialize
## Testing
Can't fully reproduce on staging previews because CSP blocks the GTM
script there (so the storage migration never fires). Verified the root
cause via production console monitoring with localStorage
monkey-patching, and confirmed the `ucData` format persists across page
loads on production.
Closes FE-2648
## What kind of change does this PR introduce?
UI update.
## What is the current behavior?
The webhook endpoint details view showed all mock deliveries in a single
table with a Studio-specific sortable header treatment, no pagination,
and uneven row heights when the retry action was absent.
## What is the new behavior?
Moves the deliveries table onto TanStack table state, adopts the shared
`TableHeadSort` header UI, keeps the existing delivery search, and adds
simple previous/next pagination controls at the bottom. The mock
deliveries are expanded so pagination and sorting can be exercised in
both organisation and project flows, and the actions column now reserves
a consistent button footprint so every row keeps the same minimum
height.
| Before | After |
| --- | --- |
| <img width="1728" height="997" alt="Webhooks Settings Chisel Toolshed
Supabase-A4712323-6FD9-471B-B1F4-234B20686018"
src="https://github.com/user-attachments/assets/2745e5fd-1ef7-4f3a-872c-1fd8d10dce41"
/> | <img width="1728" height="997" alt="Webhooks Settings Chisel
Toolshed Supabase-D482241B-F324-4EA2-9B89-133AD5E10F17"
src="https://github.com/user-attachments/assets/5bfcefd8-cb58-46c0-a863-dcf80e4da4a3"
/> |
## Additional context
This keeps the view on the Data Table path now, while aligning the
sortable headers with the design-system table pattern instead of the
older Studio-local `DataTableColumnHeader` helper.
Adding myself to the Supabase team version 2 (alphabetical order)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Update - Adding myself to the Supabase team version 2 (alphabetical
order)
## What is the current behavior?
## What is the new behavior?
## Additional context
Bug fix
## What is the current behavior?
When a user deletes a project, the `useProjectDetailQuery` in
`RouteValidationWrapper` returns an error (HTTP 404) because the project
no longer exists. This triggers the `isErrorProject` effect, which shows
a "You do not have access to this project" toast and redirects to the
home page — even though the user intentionally deleted the project.
## What is the new behavior?
The error's HTTP status code is checked before showing the toast. A 404
response (project not found / deleted) silently redirects without
showing the misleading access-denied toast. The toast is still shown for
other error codes (e.g. 403 Forbidden), where the "no access" message is
accurate.
## Additional context
Resolves FE-2831
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
docs update to add David Alvarez to humans.txt
## What is the current behavior?
David Alvarez is not currently in the humans.txt file
## What is the new behavior?
David Alvarez is now in the humans.txt file!
Reverts supabase/supabase#44109
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
New blog post for Stripe Projects
## What is the current behavior?
N/A
## What is the new behavior?
Adds a new blog post: "Supabase joins the Stripe Projects Developer
Preview" and adds Gregor Vand and Ana Mogul to authors.json.