惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
博客园 - 【当耐特】
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
D
Docker
GbyAI
GbyAI
酷 壳 – CoolShell
酷 壳 – CoolShell
WordPress大学
WordPress大学
The Cloudflare Blog
雷峰网
雷峰网
A
About on SuperTechFans
小众软件
小众软件
博客园 - Franky
博客园 - 聂微东
F
Full Disclosure
大猫的无限游戏
大猫的无限游戏
C
Check Point Blog
MongoDB | Blog
MongoDB | Blog
G
Google Developers Blog
Microsoft Azure Blog
Microsoft Azure Blog
U
Unit 42
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
V2EX
Engineering at Meta
Engineering at Meta
宝玉的分享
宝玉的分享
aimingoo的专栏
aimingoo的专栏
量子位
P
Proofpoint News Feed
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
罗磊的独立博客
Martin Fowler
Martin Fowler
D
DataBreaches.Net
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Secure Thoughts
Project Zero
Project Zero
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
C
Cybersecurity and Infrastructure Security Agency CISA
T
Tailwind CSS Blog
S
Schneier on Security
Blog — PlanetScale
Blog — PlanetScale
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
Security Latest
Security Latest
NISL@THU
NISL@THU
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
J
Java Code Geeks

Supabase Blog

AI Agents Know About Supabase. They Don't Always Use It Right. Custom OIDC Providers for Supabase Auth 100,000 GitHub stars Supabase docs over SSH Navigating Regional Network Blocks Supabase Joins the Stripe Projects Developer Preview Log Drains: Now available on Pro Supabase Storage: major performance, security, and reliability updates Supabase incident on February 12, 2026 Hydra joins Supabase X / Twitter OAuth 2.0 is now available for Supabase Auth BKND joins Supabase Supabase is now an official Claude connector Supabase PrivateLink is now available Introducing: Postgres Best Practices When to use Read Replicas vs. bigger compute Introducing TRAE SOLO integration with Supabase Supabase Security Retro: 2025 Sync Stripe Data to Your Supabase Database in One Click Building ChatGPT Apps with Supabase Edge Functions and mcp-use Own Your Observability: Supabase Metrics API Introducing iceberg-js: A JavaScript Client for Apache Iceberg Introducing Supabase for Platforms Adding Async Streaming to Postgres Foreign Data Wrappers Build "Sign in with Your App" using Supabase Auth Introducing Seven New Email Templates for Supabase Auth The new Supabase power for Kiro Introducing Supabase ETL Introducing Analytics Buckets Introducing Vector Buckets Snap, Inc. Launches Snap Cloud, Powered by Supabase Triplit joins Supabase Supabase Series E 1000 Y Combinator Founders Choose Supabase gm 👋 web3, welcome aboard to Sign in with Web3 (Solana, Ethereum) Announcing the Supabase Remote MCP Server Enterprise speed, enterprise standards with Bolt Cloud + Supabase PostgREST 13 Lovable Cloud + Supabase: The Default Platform for AI Builders Processing large jobs with Edge Functions, Cron, and Queues Defense in Depth for MCP Servers OrioleDB Patent: now freely available to the Postgres community Supabase Launch Week 15 Hackathon Winner Announcement The Vibe Coder's Guide to Supabase Environments Testing for Vibe Coders: From Zero to Production Confidence The Vibe Coding Master Checklist Vibe Coding: Best Practices for Prompting Supabase Auth: Build vs. Buy Top 10 Launches of Launch Week 15 Supabase Launch Week 15 Hackathon Storage: 10x Larger Uploads, 3x Cheaper Cached Egress, and 2x Egress Quota Persistent Storage and 97% Faster Cold Starts for Edge Functions Algolia Connector for Supabase New Observability Features in Supabase Improved Security Controls and A New Home for Security Introducing Branching 2.0 Stripe-To-Postgres Sync Engine as standalone Library Supabase Analytics Buckets with Iceberg Support Create a Supabase backend using Figma Make Introducing JWT Signing Keys Supabase UI: Platform Kit Build a Personalized AI Assistant with Postgres Announcing Multigres: Vitess for Postgres Building on open table formats Open Data Standards: Postgres, OTel, and Iceberg Simplifying back-end complexity with Supabase Data APIs PostgreSQL Event Triggers without superuser access Top 10 Launches of Launch Week 14 Supabase MCP Server Data API Routes to Nearest Read Replica Realtime: Broadcast from Database Keeping Tabs on What's New in Supabase Studio Edge Functions: Deploy from the Dashboard + Deno 2.1 Automatic Embeddings in Postgres Introducing the Supabase UI Library Supabase Auth: Bring Your Own Clerk Postgres Language Server: Initial Release Migrating from Fauna to Supabase Migrating from the MongoDB Data API to Supabase Dedicated Poolers Postgres as a Graph Database: (Ab)using pgRouting AI Hackathon at Y Combinator Calendars in Postgres using Foreign Data Wrappers Supabase Launch Week 13 Hackathon Winners How to Hack the Base! Running Durable Workflows in Postgres using DBOS database.build v2: Bring-your-own-LLM Restore to a New Project Hack the Base! with Supabase Top 10 Launches of Launch Week 13 Supabase Queues High Performance Disk Supabase Cron Supabase CLI v2: Config as Code Supabase Edge Functions: Introducing Background Tasks, Ephemeral Storage, and WebSockets Supabase AI Assistant v2 OrioleDB Public Alpha Executing Dynamic JavaScript Code on Supabase with Edge Functions ClickHouse Partnership, improved Postgres Replication, and Disk Management Live Share: Connect to in-browser PGlite with any Postgres client
Declarative Schemas for Simpler Database Management
Qiao Han · 2025-04-03 · via Supabase Blog

Declarative Schemas for Simpler Database Management

Today we’re releasing declarative schemas to simplify managing and maintaining complex database schemas. With declarative schemas, you can define your database structure in a clear, centralized, and version-controlled manner.

Declarative schemas store the final desired state of the database in .sql files that can be saved and versioned alongside a project. For example, here is the declarative schema for a classic products table:


_10

create table "products" (

_10

id bigint generated by default as identity,

_10

name text not null,

_10

category text,

_10

price numeric(10, 2) not null,

_10

created_at timestamptz default now()

_10

);

_10

_10

alter table "products"

_10

enable row level security;


Declarative schemas offer numerous benefits over making changes to your database schema directly:

  • Single pane of glass. Maintain your entire database schema in one place, reducing redundancy and potential errors.
  • Versioned migrations. Automatically generate migration files, ensuring consistent schema updated across environments. Store your declarative schema files alongside your project files in your version control system.
  • Concise code reviews. Easily review changes to tables, views, and functions without manually repeating complex migration scripts.

It's best practice to use Migrations to track and apply changes to databases. Every time you make a change, you create a new file with all the changes, keeping changes versioned and reproducible.

However, as the complexity of a database schemas grows, it becomes increasingly difficult to develop using versioned migrations as there isn't a single place to see the entire database schema.

For example, at Supabase we have a complex and frequently-updated projects table. Here's partially what it looks like with RLS enabled:


_32

create table private.projects (

_32

id bigint not null,

_32

name text not null,

_32

organization_id bigint not null,

_32

inserted_at timestamp not null,

_32

updated_at timestamp not null

_32

);

_32

_32

alter table private.projects

_32

enable row level security;

_32

_32

create policy projects_insert

_32

on private.projects

_32

for insert

_32

to authenticated

_32

with check auth.can_write(project_id);

_32

_32

create policy projects_select

_32

on private.projects

_32

for select

_32

to authenticated

_32

using auth.can_read(project_id);

_32

_32

-- Users can only view the projects that they have access to

_32

create view public.projects as select

_32

projects.id,

_32

projects.name,

_32

projects.organization_id,

_32

projects.inserted_at,

_32

projects.updated_at

_32

from private.projects

_32

where auth.can_read(projects.id);


The projects table is created in a private schema, with a public view exposed for reads. Attribute-based access control (ABAC) is implemented on top of RLS policies to ensure queries only return projects that the user has access to.

Since Postgres views are not updatable by default, we have defined trigger functions to cascade writes to the underlying table when a Supabase user creates a new project. This makes development easier because the projects view can be inserted with regular PostgREST calls while invoking the appropriate RLS policies on the underlying table.


_24

-- Triggers to update views from PostgREST: select('projects').insert({ ... })

_24

create function public.public_projects_on_insert() returns trigger

_24

as $$

_24

begin

_24

insert into private.projects(

_24

name,

_24

organization_id,

_24

inserted_at,

_24

updated_at

_24

) values (

_24

NEW.name,

_24

NEW.organization_id,

_24

coalesce(NEW.inserted_at, now()),

_24

coalesce(NEW.updated_at, now())

_24

) returning * into NEW;

_24

return NEW;

_24

end

_24

$$ language plpgsql;

_24

_24

create trigger public_projects_on_insert

_24

instead of insert

_24

on public.projects

_24

for each row

_24

execute function public.public_projects_on_insert();


This complexity slows down development velocity, as changes to the table might break other views or functions. Back in early 2022, a simple change to add a new column involved the following steps.

  1. Find the latest schema for projects table in our migration files or by querying our database.
  2. Write the alter table statement in a new migration file.
  3. Copy and update the projects view definition to include the new column.
  4. Copy and update the trigger function definition to include the new column.
  5. Add new pgTAP tests and verify that existing tests pass.
  6. Submit the new migration file for review, which would be at least a few hundred lines.

This process is tedious and it's frustrating to have multiple engineers working on the projects table concurrently. Merging PRs would result in a merge conflict that must be resolved by repeating steps 1-5.

Adopting declarative schemas gave our engineers a single pane of glass when updating database schemas. Instead of manually duplicating affected postgres entities in a migration file, we only need to change the schema definition in one place.

We then use a schema diff tool, like migra, to figure out the necessary updates to views and functions when generating the migration file.

For example, adding a new metadata column to the projects table now becomes a single line diff.


_10

--- a/supabase/schemas/projects.sql

_10

+++ b/supabase/schemas/projects.sql

_10

@@ -2,6 +2,7 @@ create table private.projects (

_10

id bigint not null,

_10

name text not null,

_10

organization_id bigint not null,

_10

+ metadata jsonb,

_10

inserted_at timestamp not null,

_10

updated_at timestamp not null

_10

);


The same process also applies to views, database functions, RLS policies, role grants, custom types, and constraints. While manual reviews are still required on the generated migration file, it has cut down our development from hours to minutes. It's also much easier to rebase on merge conflicts introduced by other PRs.

Declarative schemas are available today on Supabase.

We added the same set of tools that we used internally for the last 2 years to Supabase CLI. Whether you are just getting started with migrations or already fed up with managing hundreds of migration files, give declarative schemas a try as it will likely simplify your development process.

Check out our blog post on Postgres Language Server for better tooling and IDE integration when developing with declarative schemas.