When is REST from the database enough?

postgrest postgresql supabase
Schema driven REST versus a custom API layer

Every early stage team faces the same fork. You can stand up a custom API service and write handlers for each screen. Or you can point PostgREST at PostgreSQL and let the schema define the HTTP surface. The second path feels like cheating because it is fast. The first path feels like adulthood because it is verbose. Neither is universally correct.

The useful question is not which choice makes engineers feel serious. It is whether your product's rules live in tables and permissions, or in orchestration that should stay out of the database wire protocol.

What "REST from the database" means

Tools like PostgREST read your Postgres schema and serve REST endpoints shaped by tables, views, and functions. Filters, ordering, and embeds follow foreign keys. Roles in the database become roles on the API. Row level security decides which rows survive the filter for a given JWT or API key.

Platforms such as Supabase productize this pattern with auth, storage, and client SDKs. The architectural bet is the same: the database is not a private implementation detail. It is part of the contract with clients.

That bet pays off often enough that founders should understand it on purpose, not stumble into it because a tutorial skipped the backend chapter.

When the pattern is enough

Your UI is mostly honest CRUD. Lists, detail pages, forms, and dashboards that create and update rows without exotic side effects fit well. If the hard part is showing the right rows to the right tenant, database enforced scoping is a feature, not a shortcut.

Rules compile to constraints and policies. Foreign keys, check constraints, unique indexes, and row level security can express who may insert what. If you can describe access control as "members of org X may touch rows where org_id equals X," you are in native territory for schema driven REST.

Speed matters more than API aesthetics. MVPs, internal tools, companion apps, and admin consoles often need to exist this month. Hand writing REST for twelve tables is waste if the schema is the source of truth anyway.

One client owns the contract. Mobile and web apps built by the same team can evolve with the schema. You are not publishing a versioned public API for strangers to depend on for years.

The team respects SQL. Migrations live in Git. Policies get reviewed. Someone can explain what the anon role can do. Without that discipline, you do not have an architecture. You have exposure.

If most of those bullets are true, REST from the database is not a compromise. It is the correct boundary.

When the pattern starts to hurt

Multi step workflows with compensating actions. Charging a card, reserving inventory, and writing audit rows should commit or roll back as a unit. You can push some of that into Postgres functions. Past a certain complexity, application services with explicit steps are easier to test and reason about than a nest of triggers.

The API shape should not mirror tables. Good public APIs aggregate, rename, and hide internal normalization. Customers should not see your join table because PostgREST happily exposed it. If stable JSON contracts matter more than schema purity, a dedicated service layer earns its keep.

Heavy integration glue. Webhooks from Stripe, Salesforce sync, email providers, and PDF generators want a place to live that is not a Postgres function invoked from a REST insert. Not because Postgres cannot run code. Because operations teams need logs, retries, and deploy cadence separate from migration windows.

Authorization stories that resist SQL. Attribute based rules, dynamic feature flags, and cross tenant admin impersonation often become unreadable policy soup. Middleware in a typed language with tests beats clever RLS when the rules change weekly.

Performance paths that need bespoke batching. Auto generated endpoints encourage generic queries. Hot paths sometimes need hand tuned SQL behind a narrow route. Fighting the generator on every optimization is a signal you outgrew the pattern.

A simple test founders can run

Describe the next three features on your roadmap as sentences. For each sentence, ask: "Could a careful policy on a table make this true?"

Examples that pass:

Examples that fail:

Failures do not mean abandon Postgres. They mean add a service boundary where orchestration lives while Postgres stays the ledger.

Layers, not religions

The healthy stack is usually layered:

Layer Responsibility Typical home
Client UX, validation for humans Web or mobile app
HTTP API Stable contracts, orchestration Custom service or edge functions
Data Truth, constraints, scoped reads Postgres with RLS
Platform Auth, storage, hosting Supabase, managed Postgres, etc.

REST from the database collapses the first two rows for a while. That collapse is fine until features need orchestration or public API promises.

What is the difference between Postgres and PostgREST? stays useful here: Postgres remains the vault even when you add a custom API in front. PostgREST is one door. Your own service is another door. Pick the door based on who needs to walk through it.

Security is the hidden schedule item

Schema driven APIs fail in production when teams treat row level security as copy paste from docs. Every table needs a default deny story. Every new view needs a policy review. Service role keys must never ship to browsers.

Founders should budget time for a security pass as real as the design pass. Ask an engineer to attempt horizontal privilege escalation on staging. If they succeed in an afternoon, REST from the database is not enough yet. Policies are.

Versioning and coupling

Coupling clients to table names is acceptable early. It becomes expensive when external partners integrate or when mobile apps lag web deploys by months.

Mitigations that work without a full rewrite:

The goal is incremental boundaries, not a big bang rewrite because someone read that PostgREST does not scale philosophically.

Team skills matter as much as product shape

A team strong in SQL and migrations will outship a team fighting an ORM on the same pattern. A team that hates reviewing policies will create incidents no matter how fancy the custom API looks.

If your hire plan is two front end engineers and no one who owns the database, schema driven REST is a risk multiplier. Either plan for database ownership or plan for a conventional API layer that encodes rules in code your team already reads daily.

Cost math founders actually care about

Custom APIs cost engineer weeks up front and maintenance forever. Schema driven REST costs policy and migration discipline up front and saves handler churn early.

Neither is free at scale. Connection pooling, query review, and index work land on both paths. The difference is where bugs appear. Misconfigured RLS shows up as data leaks. Misconfigured middleware shows up as 500s. Founders should pick the failure mode their stage can detect and fix.

Decision guide

Use REST from the database when:

Add a custom API layer when:

Start schema driven and peel off services when metrics or incidents tell you to. Starting with six microservices because adulthood is a vibe burns runway without teaching you what the product actually needs.

Proof of concept that reveals the truth

Build one feature that includes a write with a side effect you care about. Try implementing it as RLS plus a view or function. If the SQL stays readable after three edge cases, you are probably fine for the next quarter. If you are fighting triggers to send email, stop and draw a service box on the whiteboard.

Also measure time to add a column end to end. Schema driven wins when that path is minutes. Custom API wins when every column requires DTOs in three repos and a changelog for partners.

The founder takeaway

REST from the database is enough when your product truth already lives in Postgres and your rules fit constraints and policies. It stops being enough when orchestration, stable public contracts, or integration complexity become the product.

The pattern is not junior or senior. It is a boundary choice. Make it explicitly, review it when the roadmap adds payments or partnerships, and keep Postgres as the system of record either way.

Work with Kleto

I am James Cowan, a product engineer and the founder of Kleto. Kleto is a product engineering agency that ships production software from strategy through handoff. We help teams decide where REST from the database is enough, where to add a service layer, and how to keep Postgres honest as the product grows. If that matches your stack, contact Kleto and we will scope a sensible first step.

Recommended

What is Supabase, and what are you actually buying? @jameslcowanmay 28 '26 supabase, postgresql
What is the difference between Postgres and PostgREST? @jameslcowanmay 19 '26 postgresql, postgrest
How do you connect a simple front end to a typed API? @jameslcowanjul 16 '26 typescript, javascript
What is SQLite good for at the edge of a system? @jameslcowanjul 13 '26 sqlite, postgresql
What is Drizzle, and why do teams treat the schema as a contract? @jameslcowanmay 12 '26 drizzle, typescript
What is Neon, and how do preview databases change shipping? @jameslcowanmay 7 '26 neon, postgresql
What is PostgreSQL, and why do products still bet on it? @jameslcowanapr 29 '26 postgresql, product-engineering
How do types go from the database to the client? @jameslcowanapr 8 '26 typescript, drizzle
What is the difference between product engineering and \"just development\"? @jameslcowanjul 9 '26 product-engineering, startups
What is observability when you do not have a platform team? @jameslcowanjul 1 '26 observability, product-engineering
What is the total cost of \"we will just use X\"? @jameslcowanjun 24 '26 smb, product-engineering
What makes an internal tool survive the first hire? @jameslcowanjun 18 '26 smb, documentation
What does \"full stack\" mean on a vendor quote? @jameslcowanjun 10 '26 smb, product-engineering
What is React, and when is the weight worth it? @jameslcowanapr 22 '26 react, javascript
What is the difference between Bun and Node? @jameslcowanapr 14 '26 bun, javascript
What is TypeScript, and why do product teams still adopt it? @jameslcowanmar 31 '26 typescript, javascript
Anthropic Trained Its Replacement @jameslcowanjun 9 '26 anthropic, ai
Karpathy Was Wrong: OpenClaw Still Outruns Its 5 Real Alternatives @jameslcowanjun 11 '26 openclaw, ai
OpenClaw: What It Is and How to Get the Most Out of It @jameslcowanjun 5 '26 openclaw, javascript
Pydantic: The Open Source Layer Quietly Running the AI Economy @jameslcowanjun 22 '26 pydantic, python
The YC S26 Deadline Just Closed. Here's What Separates the 1.5% From Everyone Else. @jameslcowanjun 17 '26 startups, yc
OpenClaw 2026.2.23: The Agent Browser Upgrade @jameslcowanjun 19 '26 openclaw, ai
Why I Skipped the CMS @jameslcowanjun 10 '26 markdown, static-site-generation
Fixing Navigation and Analytics: When Your Data Lies About User Behavior @jameslcowanjun 5 '26 htmx, javascript
HAL: Cutting 100-300KB of JavaScript by Moving Routing to Build Time @jameslcowanjun 10 '26 htmx, javascript
Mobile-First Layout That Ships: How PrimaryLayout Solves Real UX Problems @jameslcowanjun 6 '26 htmx, css
Documentation That Scales: Constitution, Contracts, and Runbooks @jameslcowanjun 8 '26 documentation, markdown
Zero-Server Analytics: How I Replaced a SaaS Bill with Netlify Functions and GitHub @jameslcowanjun 8 '26 netlify, analytics
Web Components + HTMX: A Lean Architecture for Content Sites That Ship @jameslcowanjun 10 '26 web-components, javascript
HAL: Build-Time Link Rewriting That Makes Navigation Feel Instant @jameslcowanjun 18 '26 htmx, javascript
Why I Built My Own Analytics Pipeline (And What It Actually Costs) @jameslcowanjun 18 '26 analytics, javascript
The Static Site Playbook: Shipping a Content Product on a Near-Zero Budget @jameslcowanjun 11 '26 static-site-generation, javascript
How This Site Works: Architecture for a One-Person Team @jameslcowanjun 8 '26 htmx, javascript
Web Components as a Business Decision @jameslcowanjun 11 '26 web-components, javascript
Progressive Enhancement with HTMX: Ship Fast, Degrade Gracefully @jameslcowanjun 8 '26 htmx, javascript
Less JavaScript, More Leverage: Why I Ship With a 35KB Budget @jameslcowanjun 22 '26 javascript, performance
Static Site Generation: The Business Case for Pre-Rendered HTML @jameslcowanjun 14 '26 static-site-generation, performance

Recommended

What is Supabase, and what are you actually buying? @jameslcowanmay 28 '26 supabase, postgresql
What is the difference between Postgres and PostgREST? @jameslcowanmay 19 '26 postgresql, postgrest
How do you connect a simple front end to a typed API? @jameslcowanjul 16 '26 typescript, javascript
What is SQLite good for at the edge of a system? @jameslcowanjul 13 '26 sqlite, postgresql
What is Drizzle, and why do teams treat the schema as a contract? @jameslcowanmay 12 '26 drizzle, typescript
What is Neon, and how do preview databases change shipping? @jameslcowanmay 7 '26 neon, postgresql
What is PostgreSQL, and why do products still bet on it? @jameslcowanapr 29 '26 postgresql, product-engineering
How do types go from the database to the client? @jameslcowanapr 8 '26 typescript, drizzle
What is the difference between product engineering and \"just development\"? @jameslcowanjul 9 '26 product-engineering, startups
What is observability when you do not have a platform team? @jameslcowanjul 1 '26 observability, product-engineering
What is the total cost of \"we will just use X\"? @jameslcowanjun 24 '26 smb, product-engineering
What makes an internal tool survive the first hire? @jameslcowanjun 18 '26 smb, documentation
What does \"full stack\" mean on a vendor quote? @jameslcowanjun 10 '26 smb, product-engineering
What is React, and when is the weight worth it? @jameslcowanapr 22 '26 react, javascript
What is the difference between Bun and Node? @jameslcowanapr 14 '26 bun, javascript
What is TypeScript, and why do product teams still adopt it? @jameslcowanmar 31 '26 typescript, javascript
Anthropic Trained Its Replacement @jameslcowanjun 9 '26 anthropic, ai
Karpathy Was Wrong: OpenClaw Still Outruns Its 5 Real Alternatives @jameslcowanjun 11 '26 openclaw, ai
OpenClaw: What It Is and How to Get the Most Out of It @jameslcowanjun 5 '26 openclaw, javascript
Pydantic: The Open Source Layer Quietly Running the AI Economy @jameslcowanjun 22 '26 pydantic, python
The YC S26 Deadline Just Closed. Here's What Separates the 1.5% From Everyone Else. @jameslcowanjun 17 '26 startups, yc
OpenClaw 2026.2.23: The Agent Browser Upgrade @jameslcowanjun 19 '26 openclaw, ai
Why I Skipped the CMS @jameslcowanjun 10 '26 markdown, static-site-generation
Fixing Navigation and Analytics: When Your Data Lies About User Behavior @jameslcowanjun 5 '26 htmx, javascript
HAL: Cutting 100-300KB of JavaScript by Moving Routing to Build Time @jameslcowanjun 10 '26 htmx, javascript
Mobile-First Layout That Ships: How PrimaryLayout Solves Real UX Problems @jameslcowanjun 6 '26 htmx, css
Documentation That Scales: Constitution, Contracts, and Runbooks @jameslcowanjun 8 '26 documentation, markdown
Zero-Server Analytics: How I Replaced a SaaS Bill with Netlify Functions and GitHub @jameslcowanjun 8 '26 netlify, analytics
Web Components + HTMX: A Lean Architecture for Content Sites That Ship @jameslcowanjun 10 '26 web-components, javascript
HAL: Build-Time Link Rewriting That Makes Navigation Feel Instant @jameslcowanjun 18 '26 htmx, javascript
Why I Built My Own Analytics Pipeline (And What It Actually Costs) @jameslcowanjun 18 '26 analytics, javascript
The Static Site Playbook: Shipping a Content Product on a Near-Zero Budget @jameslcowanjun 11 '26 static-site-generation, javascript
How This Site Works: Architecture for a One-Person Team @jameslcowanjun 8 '26 htmx, javascript
Web Components as a Business Decision @jameslcowanjun 11 '26 web-components, javascript
Progressive Enhancement with HTMX: Ship Fast, Degrade Gracefully @jameslcowanjun 8 '26 htmx, javascript
Less JavaScript, More Leverage: Why I Ship With a 35KB Budget @jameslcowanjun 22 '26 javascript, performance
Static Site Generation: The Business Case for Pre-Rendered HTML @jameslcowanjun 14 '26 static-site-generation, performance