releases.shpreview
Home/Supabase
Supabase

Supabase

Vector storage enabled by default; core commands now TypeScript

This release3 featuresNew capabilities1 enhancementImprovements to existing features2 fixesBug fixesAI-tallied from the release notes
Supabase CLI · v2.105.0

Supabase CLI v2.105.0 — June 4, 2026

More core commands now run on the native TypeScript shell. This release also includes improvements to vector storage and environment configuration for local development.

Improvements
  • Vector storage enabled by default — New local projects now include vector buckets. (#5421)
  • S3 and Supabase key available in Studio — Environment variables for S3 and sb key are automatically injected into your local Studio container. (#5438)
Bug fixes
  • db diff with edge-runtime containers no longer fails due to port binding. (#5424)
  • Telemetry opt-out preference now persists across CLI sessions. (#5465)
TypeScript port progress
  • Now served by the TypeScript shell: init, link, unlink, login, logout. Behavior matches the Go CLI. (#5433, #5426, #5446)

Plus 13 internal improvements and dependency updates.

Full changelog: https://github.com/supabase/cli/compare/v2.104.0...v2.105.0

Multigres v0.1 alpha: scalable Postgres OS with sharding roadmap

This release3 featuresNew capabilitiesAI-tallied from the release notes

Today we're releasing Multigres v0.1 alpha to the open source community, the first public milestone of our mission to bring Vitess-grade horizontal scaling, high availability, and operational simplicity to Postgres. It's early, it's alpha, and we're excited to get it into your hands.

This is an open-source-only release. Multigres for Supabase is coming soon.

What is Multigres?

Multigres is a scalable operating system for Postgres: it holistically manages your Postgres instances and gives you sharding, connection pooling, automatic failover, and backup orchestration.

Postgres at scale is operationally complex: You need to manage read replicas, failovers, connection limits, backups, and more. Multigres handles these chores as a single cohesive system. And when the time comes to scale, Multigres will help you shard your database and scale it horizontally.

The v0.1 alpha introduces advanced connection pooling, automatic failovers, and a Kubernetes operator for deployment.

The Multigres Operator

The Kubernetes Multigres Operator allows you to deploy and manage Multigres clusters on Kubernetes. To get started, you need a Kubernetes cluster along with a location for backups configured. The backups can be a shared file system or a cloud storage bucket like AWS S3. It is also possible to run Multigres on a local Kind cluster.

All the necessary images for running Multigres are publicly available.

High Availability

Multigres treats HA as a consensus problem, and is capable of resolving split-brain scenarios without losing commits that have succeeded. The protocol implemented by Multigres is based on generalized consensus, a model that gives you flexibilities that do not exist in traditional consensus-based systems:

  • Built on top of Postgres replication: The protocol uses unmodified Postgres replication, and yet satisfies all the strict consistency requirements of a consensus-based system.
  • User-defined durability policies: You can define arbitrarily complex durability policies. This flexibility allows you to specify the failures you are willing to tolerate without being constrained by restrictive rules like a majority quorum. For example, if you'd like your data to survive the failure of a single AZ, you can set your durability policy to be cross-zone, but still have standbys deployed in more than three zones.
  • Add or remove replicas without affecting performance: You can safely scale replicas up and down while the cluster is running. Multigres will continue to honor the durability policy you've configured without affecting performance, while also maintaining correctness.

For more information on HA, you may read the following posts:

Connection Pooling

Multigres ships its own connection pooling solution using a two-service architecture. It consists of a multigateway that accepts client connections and routes queries, and a multipooler that manages backend connections. This architecture provides some distinct advantages over a single-process pooler.

  • Traffic routing: The integration with the HA system allows multigateway to transparently route connections to the current primary. During a failover, multigateway can hold requests until a new primary is promoted, thereby minimizing errors. Additionally, you can balance read load across multiple replicas. In the future, multigateway will handle routing of traffic to different shards.
  • Context-aware pooling: Multigres does not require you to choose a pooling mode like transaction, session, etc. This is because it has a built-in parser and understands the effects of each request. This allows it to track connection state and reuse them wherever applicable. If a request requires a stateful connection, like a transaction, the connection gets pinned to that client until the stateful requirement is satisfied.
  • Per-user pools: Multigres maintains a separate connection pool per user with no shared pool and no SET ROLE impersonation. A fair-share algorithm splits a fixed connection budget across users, and pool routing is kept fast.
  • Prepared statement consolidation: Multigres deduplicates prepared statements across gateways. Postgres parses, plans, and caches a given statement once, no matter how many gateways are forwarding it.

For more information on connection pooling, you may read Two jobs, two processes: why Multigres has its own connection pooler.

Backups

Multigres uses pgBackRest for backups. Backups are taken from replicas to avoid overloading the primary.

  • Three backup types: full backups copy the entire data directory at a checkpoint; incremental backups copy only files changed since the previous backup; differential backups copy changes since the last full backup. A typical schedule runs full backups periodically with more frequent incrementals or differentials in between.
  • On-demand and scheduled: the CLI lets you list backups, trigger a manual backup, and initiate a restore. We'll soon add support for scheduled backups through the cluster spec.
  • Bootstrap: During bootstrap, Multigres automatically identifies a primary, performs a backup, and uses it to initialize the other replicas. This workflow brings up a ready-to-run cluster without any manual intervention.

To learn more about how a cluster bootstraps, you may read How a Multigres Cluster Bootstraps.

What alpha means

v0.1 is stable enough to experiment with and give feedback on. It is not yet ready for production workloads. Specific caveats:

  • We have known issues that still need to be addressed.
  • Sharding (the eventual flagship feature) is not in this release. v0.1 is a single-shard cluster with HA and pooling.
  • Future releases are not guaranteed to be backward compatible.
  • The CR API is not yet stable. Fields may change before v1.0.
  • Performance benchmarks are in progress. We'll publish numbers in a follow-up post.

Try Multigres

  1. Deploy your first cluster: a minimal CR that stands up a 3-node HA cluster.
  2. Join the community: file issues and request features at github.com/multigres/multigres. Post your thoughts in github.com/multigres/multigres/discussions to discuss features and get help.

Multigres v0.1 alpha ships; $500M Series F closes

This release1 featureNew capabilitiesAI-tallied from the release notes

Supabase has raised a $500M Series F at a $10B pre-money valuation. It's led by GIC. All existing investors joined the round, Stripe made a second investment. Georgian and Salesforce Ventures joined as new investors.

The round is for three things:

  • Accelerate development of open source / Postgres tools.
  • To support our growth.
  • Liquidity for the employees.

Open source development#

Today we're releasing Multigres v0.1 alpha. It's open source and self-hostable.

Postgres is hard to run at scale. Multigres is a scalable operating system for Postgres that provides high availability and operational simplicity. In a future release it will provide Vitess-grade horizontal scaling.

The alpha status is to signal that it's ready to try, but not yet production-ready. We'll get there in a few months. If you're running a large Postgres workload you can apply to be a Multigres partner and help shape the direction of Multigres.

Multigres will be available on the platform when it moves out of alpha. Together with our work on OrioleDB (targeting production-readiness this year), we believe that we will have a complete Postgres solution that solves many hairy Postgres problems, including bloat, connection pooling, and Jepsen-level high availability. Sharding is also on the menu - we'll share more details later.

Supabase growth#

In the past year, database launches on Supabase have grown 600%. More than 60% of new databases are launched by some sort of AI tool.

Nearly 10 million developers build on Supabase today, more than doubling since our last fundraising announcement eight months ago. Growth is accelerating since January as Claude Code and Codex expand the number of people who can build.

A lot of our growth is also thanks to our partners, platforms that build on top of Supabase. Supabase for Platforms has been the fastest growing product over the last year.

Managing infrastructure at our scale brings a unique set of challenges. We're using this funding to invest in the not-so-visible platform features: performance, reliability, and support teams to help our customers. Postgres can be hard to manage, even for experienced DBAs, and we're investing in tooling that helps builders run their databases autonomously.

Employee secondaries#

Supabase has employees in over 50 countries now. We are always looking for the "best person for the job", no matter where they live. We don't do geo-adjusted salaries - people get paid for the result of their work, not the city they live in.

We approach stock options with a similar mindset. Employees have 10 years to exercise, even if they decide to leave. In every round, we offer our employees to sell up to 25% of their vested stock. This provides liquidity long before we reach the public market.

Check out our careers page if you'd like to join our global remote and async team.

To the community#

I work at Supabase because we're open source. Building for a community of builders is the thing I care most about. One of Supabase's principles is to support existing tools, working collaboratively with the open source community.

Thank you to everyone who has helped along the way, especially those who have contributed directly or indirectly to the tools that make up the Supabase ecosystem.

Auth mutex replaced with commit guard; expired JWT errors fixed

This release3 featuresNew capabilities4 fixesBug fixesAI-tallied from the release notes
Supabase JS · v2.107.0

2.107.0 (2026-06-02)

🚀 Features
  • auth: remove navigator.locks-based mutex; introduce commit guard + dispose() (#2392)
  • realtime: allow httpSend to send binary payload (#2400)
  • supabase: update X-Client-Info to structured metadata format (#2359)
🩹 Fixes
  • auth: return AuthInvalidJwtError from getClaims for expired JWT (#2395)
  • auth: recognize ?error= redirects in implicit grant gate (#2407)
  • auth): revert fix(auth: encode client-id in oauth requests (#2383, #2417)
  • postgrest: return a structured error for non-JSON body on successful responses (#2398)
  • release: pin workspace:* sibling deps before JSR publish (#2418)
  • release: publish gotrue-js legacy mirror via pnpm (#2419)
❤️ Thank You
  • Claude Opus 4.7 (1M context)
  • Claude Sonnet 4.6
  • Eduardo Gurgel
  • Guilherme Souza
  • Katerina Skroumpelou @mandarini
  • Omar Al Matar @Bewinxed
  • youcef zr @youcefzemmar
  • youcefzemmar

2.102.0 (2026-05-29)

Bug Fixes
  • cli: restore completion subcommand tree in legacy shell (#5368) (8bc660e), closes #compdef
  • cli: skip identity stitch in CI to stop ephemeral-env identify spam (#5366) (ca47a15), closes #5329
  • cli: support legacy migrations alias (#5355) (0d53df0)
  • cli: support older x64 CPUs (#5339) (56b598b)
  • cli: update effect beta (#5380) (c1c0ed5)
  • config: interpolate env() refs before schema decode (#5341) (d9f31cc), closes #5281
  • docker: bump supabase/postgres from 17.6.1.106 to 17.6.1.130 in /apps/cli-go/pkg/config/templates (#5362) (bc3c9c7)
  • docker: bump supabase/postgres from 17.6.1.130 to 17.6.1.131 in /apps/cli-go/pkg/config/templates (#5372) (2b87d72)
  • docker: bump the docker-minor group across 1 directory with 9 updates (#5365) (a47344e)
  • docker: bump the docker-minor group in /apps/cli-go/pkg/config/templates with 2 updates (#5371) (2bc4aea)
  • docker: repair mirror image workflow dispatch (#5363) (af9cbf1)
  • docker: restore Dependabot image updates (#5360) (5362083)
Features
  • cli: add support for vector buckets in CLI operations (#5230) (7a2f6d6)
  • cli: align legacy telemetry payload with Go CLI (#5359) (6928009)
  • cli: port backups list and restore to native TypeScript (#5331) (627e534)
  • cli: port branches commands to native TypeScript (#5374) (a0adb4d)
  • cli: port network-restrictions commands to native TypeScript (#5367) (c87d52b)
  • cli: port orgs commands to native TypeScript (#5379) (f03d18e)
  • cli: port secrets commands to native TypeScript (#5357) (0cfdb72), closes #5341
  • cli: port ssl-enforcement to native TypeScript (#5340) (c16564a)
  • cli: port sso commands to native TypeScript (#5375) (d5a1e70)
  • config,stack: add auto_expose_new_tables configuration option (#5239) (bbc5523), closes supabase/supabase#45329

There has been a growing trend of supply chain attacks on Node Package Manager (NPM). In addition, we have seen other creative attacks, including a typosquat package named supabase-javascript that appeared on npm, copying our name to phish developers. We reported it. npm took it down a few hours later, long enough that the package picked up real downloads.

If you build on Supabase, this matters to you. Edge Functions pull from npm. The Supabase CLI is on npm. supabase-js, @supabase/ssr, and @supabase/server are all on npm. Any of these is a credential leak waiting for the wrong update to land.

This post lays out what we are doing about it and what you should do today.

What we are doing about it at Supabase#

We kicked off a coordinated response across the company. The work in flight:

  • Publishing a canonical security guide in our docs. A single, agent-readable page that tells you exactly what to do.
  • Hardening our own GitHub Actions. Our security team finished a pass on pull_request_target usage across the Supabase org months ago and is close to enforcing pinned action SHAs across every repo.
  • Adding security notes to secret-handling APIs. TSDoc and JSDoc on functions like createClient so editor hovers warn when you are working with sensitive credentials.
  • Comms across every channel. Our goal is to educate as many people as we can, whether or not they are Supabase customers.

How npm supply chain attacks actually happen#

Supply chain attacks share a shape. The attacker does not break into your computer. They get you to invite their code in, and they do that by getting their code into a package you already trust. The recipes vary, but the three most common patterns are these:

  • Maintainer compromise. An attacker steals an npm publish token or phishes a maintainer, then publishes a new version of a popular package with malicious code added. The next time you run npm install against that range, you are running their code.
  • Typosquatting. An attacker registers a package name a few letters away from a real one, like supabase-javascript instead of @supabase/supabase-js. They wait for a developer or, increasingly, an AI coding agent to mistype the name. AI agents hallucinate package names regularly, and that is now a primary attack vector against teams that vibe-code their dependencies.
  • Build pipeline compromise. This is what hit TanStack. An attacker found a vulnerable GitHub Actions workflow, poisoned the build cache from a fork PR, and waited for the next legitimate release run to pick up the poisoned cache and publish their code under the real maintainer's identity. No stolen tokens. No compromised laptops. The attacker rode the official release train.

Once the malicious code lands on disk in your node_modules, npm's lifecycle scripts run it. By the time npm install returns, the attacker has already read your environment variables, your AWS instance metadata, your kubeconfig, your .npmrc token, your .git-credentials, and your SSH private keys. The TanStack payload exfiltrated through the Session messenger network, which is end-to-end encrypted and has no fixed command-and-control address. You cannot block it at the firewall.

The TanStack postmortem describes the full chain and is worth reading if you maintain a public open source project. The short version: every link in the chain (a pull_request_target workflow, an unsecured Actions cache, a long-lived OIDC publish token) was a known issue with public mitigations. The attack worked because nobody had connected the dots in advance.

Other things you should do today#

Most of what follows takes minutes. The goal is layered defense: no single mitigation stops every attack, but together they raise the cost enough that attackers go bother someone else.

Upgrade to pnpm 11 (or the npm v11 equivalent)#

pnpm 11 sets minimumReleaseAge to 24 hours by default, blocks exotic subdependencies by default, and ships a new Allow Builds model that controls which dependencies are permitted to run install scripts. If your AI coding agent picked pnpm 10.x for you, fix that. Tell it to use pnpm 11.

Then set minimumReleaseAge higher than the default. Three to seven days is a reasonable starting point for most projects. Most malicious npm packages are caught and pulled within twenty-four to forty-eight hours, so a three-day window catches the long tail of detections without throttling legitimate updates too much. Configure it in your project's pnpm-workspace.yaml or .npmrc:

minimumReleaseAge: 4320 # minutes, equals 3 days
Pin versions, especially for security-sensitive dependencies#

The ^ and ~ ranges in your package.json are a polite way of telling npm "trust me, take the next minor or patch version." Supply chain attacks exploit exactly that trust. Pin exact versions for anything that touches authentication, secrets, networking, or user data. Use ^ only where you actively want updates and have a process to vet them.

Commit your lockfile and review changes to it#

A lockfile records exactly which version of which package, with which hash, you installed. If an attacker republishes a tarball under the same version number, the hash mismatch fails the install. Commit pnpm-lock.yaml, package-lock.json, or yarn.lock to your repo. Treat lockfile diffs as code review surface, not noise. A pull request that bumps fifty transitive dependencies for no obvious reason deserves a careful read before it merges.

Disable npm install scripts where you can#

Most supply chain payloads run through preinstall, install, or postinstall lifecycle scripts. If your project does not need them, turn them off globally:

npm config set ignore-scripts true

Or scope it to the project via .npmrc:

ignore-scripts=true

The trade-off is that some packages with native code (bcrypt, sharp, and similar) will not build without scripts. Use pnpm's Allow Builds model to allowlist the specific packages you actually need rather than allowing every package on the registry to run code at install time.

Verify package names every single time you install#

Typosquats target the moment of carelessness. Before you pnpm add anything, especially anything an AI agent suggested, check that:

  • The scope is correct. Official Supabase packages live under @supabase/. A package named supabase-javascript or supabase-server without the scope is not ours and never has been.
  • The maintainer is the expected one. The npm page lists current maintainers; a brand-new maintainer on a long-established package is a signal worth a closer look.
  • The download counts and the linked GitHub repo match what you expect for a real, established package.
Pin your GitHub Actions to commit SHAs, not tags#

If you maintain a public repo, this is the single biggest change you can make. A tag like @v5 is a moving target. The maintainer of that action (or an attacker who compromised that maintainer) can republish the tag with new code, and your workflow will pick it up on the next run. Pin to the full commit SHA instead:

- uses: actions/checkout@1f9a0c22da41e6ebfa534300ef656b67ce0c5b94 # v6.0.2

Renovate and Dependabot both understand this syntax and will update the comment when a new release is published, so you still get visibility without giving up safety.

Avoid pull_request_target with code checkout#

If your workflow uses pull_request_target and then checks out code from the PR, you are running attacker-controlled code in a context that has access to your repo's secrets and cache. This is the exact pattern that compromised TanStack. Use pull_request for anything that touches PR code. Reserve pull_request_target for trusted, no-checkout operations like labeling or commenting on the PR.

Rotate credentials if you think you were exposed#

If you ran npm install on a day when a package you depend on turned out to be compromised, treat the install host as potentially compromised too. Rotate everything reachable from that machine: AWS, GCP, Kubernetes, Vault, GitHub, npm, SSH, and any Supabase service-role keys. Audit your service-role key usage in the Supabase dashboard for access patterns you do not recognize. It is an annoying afternoon. It is not as annoying as a customer breach.

Consider a scanner as a second line of defense#

Tools like Socket.dev, npq, and Snyk monitor the npm registry and flag suspicious package behavior in real time. None of them are a silver bullet, and none of them substitute for the practices above. They are a useful second line of defense for teams that already have the basics in place.

Closing thought#

This kind of attack will keep happening. The cost of pulling one off keeps dropping; the payoff (credentials to dozens of production systems in a single shot) keeps rising. The good news is that the defenses are well understood, cheap to implement, and effective when stacked. Pin your versions. Wait for the dust to settle on new releases. Lock your CI down. Verify what you install. Tell your AI agents to do the same.

If you have suggestions, requests, or your own war stories about how you handle this on your team, find me on Discord or on Twitter.

Prompt for your coding agent#

Paste this into Claude Code, Codex, Cursor, or whatever agent you use. Read every change before you accept it. Do not skim.

Audit this repo for npm supply-chain hygiene. Apply the changes below and report what you did. Do not push, open PRs, install new dependencies, or rotate credentials without explicit approval.

Package manager:

- Upgrade to pnpm 11+ (or the latest yarn / npm / bun) if older.
- Set a 7-day quarantine on new versions for the package manager in use:
 - pnpm: `minimumReleaseAge: 10080` in `pnpm-workspace.yaml`.
 - npm: `min-release-age=7` in `.npmrc`.
 - yarn (berry): `npmMinimalAgeGate: '7d'` in `.yarnrc.yml`.
 - bun: `minimumReleaseAge = 604800` under `[install]` in `bunfig.toml`.
- Block lifecycle scripts by default. pnpm: declare an explicit `allowBuilds` list in `pnpm-workspace.yaml`. npm/bun: set `ignore-scripts=true`. yarn defaults to `enableScripts: false` — confirm it is not overridden.
- Block non-registry transitive refs. pnpm: `blockExoticSubdeps: true`. npm: set `allow-git=root`, `allow-remote=root`, `allow-file=root`, `allow-directory=root` in `.npmrc`. yarn: use `approvedGitRepositories` as an explicit allowlist.
- Pin the package manager itself: set `packageManager` in `package.json` to an exact version plus sha512 hash (e.g. `pnpm@10.4.1+sha512.<hash>`).

Lockfile and dependencies:

- Confirm `pnpm-lock.yaml`, `package-lock.json`, or `yarn.lock` is committed (not gitignored). CI installs must use `--frozen-lockfile` (pnpm/yarn) or `npm ci`. Flag any job that runs a non-frozen install.
- For dependencies handling auth, secrets, networking, crypto, or user data, replace `^`/`~` ranges with exact versions. List what you changed.
- Verify every Supabase import uses the exact `@supabase/` scope. Flag unscoped lookalikes (`supabase-js`, `supabase-javascript`, etc.) as possible typosquats.

GitHub Actions (if present):

- Repin every third-party `uses:` reference to a 40-character commit SHA, with the original tag as a trailing comment.
- Flag every workflow using `pull_request_target` that checks out PR code or runs PR-controlled build steps. Propose a `pull_request` rewrite. Do not silently change trigger types.
- Add a non-blocking `npm audit signatures` step to install workflows.

Flag for human (do not auto-enable):

- Dependabot alerts and secret scanning, if disabled.

Report:

- One line per file changed, with the reason.
- A separate list of items flagged for human review rather than automatically changed.

2.101.0 (2026-05-21)

Bug Fixes
  • alias and telemetry docs link (#5301) (efb0949)
  • ci: drop co-incident tags in backfill-release-notes so it picks the right baseline (#5321) (88ed52d)
  • cli: inject Sentry DSN and PostHog credentials into Go binary (#5314) (aa2b0f2)
  • cli: inject version into Go binary via ldflags (#5313) (801729b), closes #5308
  • cli: require hostname (#5328) (b2f10f0)
  • cli: stabilize smoke tests with docker image caching and retries (#5258) (55e3406)
  • correct local db push text (#5280) (9ab8670)
Features
  • cli: Add --no-apply flag for db schema declarative sync command (#5220) (46cc858), closes #5218

2.106.0 (2026-05-18)

🚀 Features
  • supabase: W3C/OpenTelemetry trace context propagation (#2163)
🩹 Fixes
  • auth: return null user and session for email_change single-confirmation verifyOtp (#2378)
  • release: mark @supabase/tracing private and snapshot it for JSR (#2370)
  • storage: make StreamDownloadBuilder implement Promise and memoize executor (#2367)
❤️ Thank You
  • Claude Sonnet 4.5
  • Guilherme Souza
  • Katerina Skroumpelou @mandarini
  • oniani1

2.105.4 (2026-05-08)

🩹 Fixes
  • auth: return null from getItemAsync on JSON parse failure (#2336)
  • postgrest: restore non-Error abort detection in fetch catch (#2335)
  • realtime: guard sessionStorage access in restricted-storage browsers (#2339)

Supabase is now an official app in ChatGPT. Connect your Supabase projects and manage your entire database infrastructure by telling ChatGPT what you need.

With the Supabase ChatGPT app, you can execute SQL queries, modify schemas, deploy edge functions, manage branches, and troubleshoot your projects without leaving your conversation with ChatGPT.

Ask ChatGPT to check security advisors on your project and fix any issues. Request a schema change and ChatGPT executes it. Deploy an edge function with a single prompt.

What you can do#

The Supabase ChatGPT app includes 29 tools:

  • Database management: Execute SQL queries on Postgres databases, design and modify table schemas, list tables and extensions, get security recommendations.
  • Project operations: List and create projects, get cost estimates, pause and restore projects, access real-time logs.
  • Branching and migrations: Create development branches, merge changes, rebase and reset branches, list and apply migrations.
  • Edge functions: List, deploy, and manage serverless functions.
  • Documentation: Search Supabase docs directly from ChatGPT.

You can also pair the app with ChatGPT Projects to scope a conversation to a specific Supabase project. Set your project reference in the project instructions once, and every chat in that project connects to the right database automatically.

Getting started#

In ChatGPT, open the app directory and search for Supabase, or go directly to the app listing. Authorize ChatGPT to access your Supabase organization.

The app works on all Supabase plans and paid ChatGPT plans (Plus, Pro, Team, Enterprise).

If you don't have a Supabase account yet, start your project for free at supabase.com. Then connect it to ChatGPT and manage your projects by describing what you need.

Read the documentation at supabase.com/docs/guides/getting-started/mcp.

Supabase · v1.26.05

Here's everything that happened with Supabase in the last month:

Custom OAuth/OIDC providers for Supabase Auth

<img width="1200" height="630" alt="customoidcproviders" src="https://github.com/user-attachments/assets/97a1bc92-f8a9-4bf4-894d-ede6a762ab2b" />

Connect any OAuth2 or OpenID Connect identity provider to your Supabase project, including GitHub Enterprise, regional IdPs, and any standards-compliant provider, with PKCE enabled by default.

[Blog]

New tables in the public schema are no longer auto-exposed to the Data API

<img width="1200" height="630" alt="schematables" src="https://github.com/user-attachments/assets/e4b0c2dc-8c7b-4361-b2fb-6eb48ff6d098" />

Starting April 28, new Supabase projects can opt out of automatic Data API exposure for public schema tables. Explicit Postgres grants are now required to make a table reachable via PostgREST or GraphQL. This becomes the default for all new projects on May 30.

[GitHub Discussion]

Supabase is now ISO 27001 certified

<img width="1200" height="630" alt="security" src="https://github.com/user-attachments/assets/34e5e97f-af0c-46f8-86b8-db09267c0b6f" />

Supabase is certified to ISO/IEC 27001:2022, covering the information security management system across the entire platform.

[Blog]

Stripe Sync Engine moves to Stripe

<img width="1200" height="630" alt="stripesyncenginethumb" src="https://github.com/user-attachments/assets/3597cc93-7da2-4d0f-875c-eb1185997d8d" />

The Stripe Sync Engine, originally built by Supabase, is now part of the Stripe GitHub org. It is open source and maintained by Stripe going forward.

[Blog]

Supabase brand survey

<img width="2400" height="1260" alt="baseline-brand-survey" src="https://github.com/user-attachments/assets/8cd9c5de-bb4a-4eb5-905d-c1baefbe24ff" />

Help shape the direction of Supabase. The brand survey takes a few minutes and closes soon.

[Take the survey]

@supabase/server

<img width="1200" height="630" alt="LinkedIn X (1)" src="https://github.com/user-attachments/assets/0c97bc2d-e4d3-47c4-bee0-9611a3ad0370" />

A new SDK that handles auth, client creation, CORS, and context injection across runtimes. Works on Edge Functions, Vercel Functions, Deno, Bun, and Cloudflare Workers.

[Blog] [Docs]

Quick Product Announcements

  • The Supabase app in the Stripe Marketplace is now generally available. [Stripe Marketplace]
  • Branching without Git is now the default. Create branches directly from the dashboard without a GitHub integration. [Blog]
  • Data API settings revamped: new per-table and per-function toggles let you control which tables are exposed to PostgREST and GraphQL, with a default-privileges switch at project creation. [Docs]
  • The Supabase changelog now has RSS feeds, tag filtering, and a .md feed, plus links to copy any entry as Markdown or ask Claude/ChatGPT. [Changelog]
  • Wrappers v0.6.0 ships with a new OpenAPI FDW, Snowflake timeout support, Clerk CRUD, and several bug fixes. [GitHub] [Docs]
  • Supabase Agent Skills: an open-source set of instructions that teach AI coding agents how to build on Supabase correctly. [Blog]
  • Terraform Provider v1.9.0 adds Edge Functions resource, Edge Function secrets resource, and a network bans data source. [Docs]

Made with Supabase

  • Replist: Track your repertoire, sharpen your practice, and connect with the musicians you play with. [Website]
  • Grepture: Trace, evaluate, and protect every LLM call. Drop-in SDK. 80+ detection rules. [Website]
  • Causo: Agents that connect you with best fit partners at VCs. [Website]
  • Screenfully: An app demo creator on your phone. No need to connect to a Mac. [Website]
  • Anamap: Cartos by Anamap is an AI agent that investigates your dashboards, site behavior, and code releases to find the root cause of metric drops in plain English. [Website]
  • Crewform: Build your AI team with Crewform. Orchestrate specialized, autonomous agents to collaborate on complex tasks and connect outputs to your stack. [GitHub]

Community Highlights

  • The Supabase GitHub repo hit 100K stars and 8 million developers. [Blog]
  • Introducing the OSSCAR: An index of the fastest-growing open-source orgs. [Blog]
  • The State of Startups 2026 survey is still open. [Survey]
  • How I Scaled My NextJS + Supabase App to 25,000 Users [YouTube]
  • Stop Building Custom Auth — Auth0 vs Supabase: One Saved Us 3 Months of Engineering Work [Blog]

Today we're releasing @supabase/server in public beta.

This is a new package that handles auth verification, client setup, request context, and common server-side boilerplate for you. It works across Edge Functions, Vercel Functions, Cloudflare Workers, Hono and Bun.

We anonymously analyzed 25,000 deployed Edge Functions and saw the same pattern everywhere: developers were rebuilding the same setup code over and over just to get to their actual business logic.

Most functions needed to:

  • Create a Supabase client with SUPABASE_ANON_KEY
  • Create another admin client with SUPABASE_SERVICE_ROLE_KEY that can bypass Row Level Security
  • Verify the JWT
  • Parse claims
  • Handle CORS
  • Wire up auth context
  • Copy/paste the same _shared/*.ts files between functions

With @supabase/server you just declare who can call your endpoint and get a fully initialized context back:

  • User-scoped Supabase client
  • Admin client with service role access
  • Verified user identity
  • JWT claims
  • Built-in request/auth helpers
import { withSupabase } from 'npm:@supabase/server'

// Typical Deno.serve usage
Deno.serve(
  withSupabase({ auth: 'user' }, async (req, ctx) => {
    const { data } = await ctx.supabase.from('todos').select()
    return Response.json(data)
  })
)

// New fetch style handler usage
export default {
  fetch: withSupabase({ auth: 'user' }, async (req, ctx) => {
    const { data } = await ctx.supabase.from('todos').select()
    return Response.json(data)
  }),
}

Note that export default { fetch } is equivalent to Deno.serve(...). Both define a request handler. We use export default throughout this post because it works across Edge Functions, Workers, and Bun. If you prefer Deno.serve, you can keep using it — it's still supported on Edge Functions.

How it works#

At the core of @supabase/server is the SupabaseContext: a request context that includes everything most Edge Functions need, already configured for you.

That includes:

  • A user-scoped Supabase client
  • An admin client with service role access
  • Verified user identity
  • JWT claims
  • Auth metadata

@supabase/server gives you multiple ways to get a SupabaseContext. The most common is withSupabase, a wrapper that handles auth, client creation, and CORS before your handler runs:

import { withSupabase } from 'npm:@supabase/server'

export default {
  fetch: withSupabase({ auth: 'user' }, async (req, ctx) => {
    const { data } = await ctx.supabase.from('todos').select()
    return Response.json(data)
  }),
}

If you need more control over error handling and responses, you can also call createSupabaseContext directly:

import { createSupabaseContext } from 'npm:@supabase/server'

export default {
  fetch: async (req) => {
    const { data: ctx, error } = await createSupabaseContext(req, { auth: 'user' })
    if (error) return Response.json({ error: error.message }, { status: error.status })

    const { data } = await ctx.supabase.from('todos').select()
    return Response.json(data)
  },
}

Both approaches give you the same SupabaseContext. No shared utility files. No environment variable management. No manual JWT verification.

What's in the context#

Every withSupabase handler receives a ctx object with two pre-configured clients:

ctx.supabase — a user-scoped client that automatically respects RLS policies ctx.supabaseAdmin — an admin client using the service role for privileged operations

No manual client setup, JWT verification, or environment variable wiring required.

The full context looks like this:

interface SupabaseContext {
  supabase: SupabaseClient
  supabaseAdmin: SupabaseClient
  userClaims: UserIdentity | null
  jwtClaims: JWTClaims | null
  authMode: AuthMode
}

Declarative access control#

With @supabase/server, authentication happens before your handler runs.

You declare who is allowed to call the endpoint, and the package handles verification automatically.

For example, this endpoint allows unauthenticated requests:

export default {
  fetch: withSupabase({ auth: 'none' }, async (_req, _ctx) => {
    return Response.json({ status: 'ok' })
  }),
}

This endpoint requires a valid user JWT:

export default {
  fetch: withSupabase({ auth: 'user' }, async (req, ctx) => {
    const { data } = await ctx.supabase.from('todos').select()
    return Response.json(data)
  }),
}

If the request does not include a valid user token, the request is rejected before your handler executes.

Here's all of the auth modes included in the package:

// authenticated users only (default)
withSupabase({ auth: 'user' }, handler)

// no auth required, good for webhooks and health checks
withSupabase({ auth: 'none' }, handler)

// server-to-server with secret key
withSupabase({ auth: 'secret' }, handler)

// with publishable key
withSupabase({ auth: 'publishable' }, handler)

// accept either a user JWT or a secret key
withSupabase({ auth: ['user', 'secret'] }, handler)

Your function's security model is visible in one line.

Adopting new auth keys without the boilerplate#

Last year we improved project security with asymmetric JWT Signing Keys and new API keys. Better security for every project, but migrating existing functions was hard.

You had to install jose, configure a JWKS endpoint, build your own auth middleware, expose new secrets, and update every function individually.

We fixed it. @supabase/server handles new key validation and JWT verification internally. You adopt the package and the new security model comes with it. No jose. No JWKS configuration. No manual secret setup.

export default {
  // auth: 'user' will handle incoming user JWT validation for you
  fetch: withSupabase({ auth: 'user' }, async (req, { supabase }) => {
    const { data } = await supabase.from('subscriptions').select('*')
    return Response.json(data)
  }),
}

Now you get support for the new auth keys without manual JWT verification. Delete your shared utility files and focus on business logic.

Same code, every runtime#

withSupabase returns a standard (Request) => Promise<Response> handler. It works with any runtime that supports the Web API pattern.

Edge Functions, Vercel Functions, and Cloudflare Workers:

import { withSupabase } from '@supabase/server'

export default {
  fetch: withSupabase({ auth: 'user' }, handler),
}

On Edge Functions, declare the dependency in deno.json to import @supabase/server from npm:@supabase/server.

Hono (with the included adapter):

import { withSupabase } from '@supabase/server/adapters/hono'
import { Hono } from 'hono'

const app = new Hono()

app.get('/todos', withSupabase({ auth: 'user' }), async (c) => {
  const { supabase } = c.var.supabaseContext
  const { data } = await supabase.from('todos').select()
  return c.json(data)
})

export default { fetch: app.fetch }

Composable primitives#

Most developers don't need anything beyond withSupabase or createSupabaseContext. But you can use the underlying primitives directly.

import {
  createAdminClient,
  createContextClient,
  resolveEnv,
  verifyAuth,
} from '@supabase/server/core'

These are useful when you need more control: multiple routes with different auth, custom response headers, or domain-specific wrappers like MCP servers.

Here's an Edge Function with per-route auth:

import { createContextClient, verifyAuth } from '@supabase/server/core'

export default {
  fetch: async (req) => {
    const url = new URL(req.url)

    if (url.pathname === '/health') {
      return Response.json({ status: 'ok' })
    }

    if (url.pathname === '/todos') {
      const { data: auth, error } = await verifyAuth(req, { auth: 'user' })
      if (error) return Response.json({ error: error.message }, { status: error.status })

      const supabase = createContextClient(auth.token)
      const { data } = await supabase.from('todos').select()
      return Response.json(data)
    }

    return new Response('Not found', { status: 404 })
  },
}

These are the same primitives that power withSupabase. Teams building MCP servers, custom middleware, or framework adapters can compose them into their own patterns.

One pattern for humans and AI agents#

We designed @supabase/server with agentic development in mind. Every function follows the same structure: declare access, receive context, write logic.

During internal testing, Claude Code migrated an entire project's Edge Functions to @supabase/server in a single prompt. That included adopting new API keys, removing shared utility files, and switching every function to withSupabase. All functions worked on the first run.

When every function looks the same, agents produce correct code from a single example.

FAQ#

Does this replace @supabase/ssr?

No. @supabase/ssr handles cookie-based session management for frameworks like Next.js and SvelteKit. @supabase/server handles stateless, header-based auth for Edge Functions, Workers, and other backend runtimes. The two packages coexist and are not replacements for each other. Deeper integration with @supabase/ssr is on the roadmap.

If you would like to adopt the DX that this package provides, check our SSR frameworks documentation for implementation references.

Which runtimes does this support?

Any runtime or platform that supports the standard Request/Response Web API. withSupabase returns a standard (Request) => Promise<Response> handler, so it works on Supabase Edge Functions, Vercel Functions, Cloudflare Workers, Bun, Deno and more.

Is Hono the only supported framework?

No. Hono was the first framework adapter we shipped, and we have already merged a community PR for the H3 adapter. We expect to accept more community-contributed adapters.

See more in our adapters documentation.

Where is the documentation?

The package ships with full documentation in the GitHub repo. We're also working on adding guides to the Supabase docs.

What about environment variables?

On the Supabase platform and Local Development (CLI), your Edge Functions will receive the required environment variables to work out of the box (SUPABASE_PUBLISHABLE_KEYS, SUPABASE_SECRET_KEYS, SUPABASE_JWKS).

In local development or self-hosted environments, use the same plural form: SUPABASE_PUBLISHABLE_KEYS instead of SUPABASE_ANON_KEY, SUPABASE_SECRET_KEYS instead of SUPABASE_SERVICE_ROLE_KEY.

Check out the environment variables documentation for more details.

How can I leave feedback?

Open an issue on the GitHub repo or join the conversation in Discord.

Get started#

Install the package and the AI skill:

npm install @supabase/server@latest
npx skills add supabase/server

The skill gives Claude Code, Codex, Cursor and any agentic coding tool full context about the API surface, patterns, and migration paths. From there, you can prompt your way through most tasks.

Analyze all Edge Functions, and plan a full migration to use
the new API keys with @supabase/server

Scaffold a new REST API with Hono:

Create a Hono API with @supabase/server that has CRUD
endpoints for a todos table, using per-route auth

Add a protected Edge Function with admin operations:

Create an Edge Function that accepts user or secret key auth,
reads from a user's profile with RLS, and writes audit logs
with the admin client

Or write it by hand:

import { withSupabase } from 'npm:@supabase/server'

export default {
  fetch: withSupabase({ auth: 'user' }, async (req, ctx) => {
    const { data } = await ctx.supabase.from('todos').select()
    return Response.json(data)
  }),
}

@supabase/server is in public beta. We're looking for feedback on the API surface, the adapter patterns, and edge cases we haven't hit yet.

Check out the GitHub repo and the docs and let us know what you build.

Changelog

Bug fixes
  • e4a7ace0226dfd7ee8886ebc550a4b5c476c047e: fix: mailer links regression (#5166) (@jgoux)
Others
  • 893c2840996c7ec8cfaa38a2907b973a7859957c: chore: sync API types from infrastructure (#5160) (@supabase-cli-releaser[bot])
  • 9da7facef2f648ef2a58b61731327c3ba2ce31af: fix (@7ttp)
  • f6c1529132e6d3f5d397db6e2830771966133e4a: test (@7ttp)
Last Checked
1h ago
Category
Tracking since Jul 2, 2020