How do you connect a simple front end to a typed API?

typescript htmx postgrest product-engineering javascript
Simple front end talking to a typed API

Teams waste months arguing frameworks when the real question is simpler: how does the browser talk to the source of truth without lying about shapes and permissions? You can answer that with a heavy SPA and a custom backend. You can also answer it with a thin UI and a typed API that stays honest as the product grows.

This is the seam between "ship a screen" and "own a system."

Start from the contract, not the widgets

Pick the contract first:

UI libraries come and go. A muddy contract stays muddy in every library.

How types flow from the database to the client covers the vertical slice. Here the focus is the front edge of that slice.

Pattern A: schema driven HTTP

If your API is mostly table shaped, PostgREST or a Supabase style layer can expose Postgres directly. The front end calls HTTP. Types can be generated from OpenAPI or from a shared schema package.

This shines for admin tools and internal products. It struggles when the screen needs a choreography the database should not own.

Pattern B: small API, shared types

A modest Node or Bun service owns routes. Types are shared from a package or generated from Zod, TypeBox, or similar. The front end imports those types or OpenAPI clients.

You pay for a thin backend in exchange for a place to put workflows, webhooks, and rules that are not row shaped.

Pattern C: HTML first with progressive enhancement

A simple front end does not have to mean a giant client runtime. Server rendered HTML plus small bursts of JavaScript (or HTMX style swaps) can talk to the same typed API. The browser gets documents and fragments. The API still enforces auth and shapes.

This site uses that philosophy for content. Product apps can use the same instinct: keep the client humble when the server already knows the truth.

What "typed" should mean to a founder

Typed does not mean "we use TypeScript somewhere." It means a change in the data contract fails loudly in CI before customers feel it. If your UI can send fields the server no longer accepts and nobody notices until production, you do not have a typed boundary. You have vibes.

A practical wiring checklist

  1. Auth before cosmetics. Tokens, cookies, or session headers with clear rules.
  2. One base URL per environment. Staging and production are not optional.
  3. Generated or shared types in CI. Break the build when the contract drifts.
  4. Error shapes the UI can show. Silent JSON failures train users to distrust the app.
  5. Idempotency on money and invites. Retries happen. Plan for them.

Choosing simplicity on purpose

If your team is small, prefer the least moving parts that still protect the contract. A simple front end plus a clear API beats a fashionable client that reimplements business rules in three stores.

When REST from the database is enough, use it. When it is not, read When is REST from the database enough? and put a real service on the awkward paths only.

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 wire thin clients to honest APIs without accidental architecture. If that matches your stack, contact Kleto and we will scope a sensible first step.

Recommended

What is TypeScript, and why do product teams still adopt it? @jameslcowanmar 31 '26 typescript, javascript
How do types go from the database to the client? @jameslcowanapr 8 '26 typescript, drizzle
What is React, and when is the weight worth it? @jameslcowanapr 22 '26 react, javascript
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
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
How This Site Works: Architecture for a One-Person Team @jameslcowanjun 8 '26 htmx, javascript
Progressive Enhancement with HTMX: Ship Fast, Degrade Gracefully @jameslcowanjun 8 '26 htmx, javascript
What is SQLite good for at the edge of a system? @jameslcowanjul 13 '26 sqlite, postgresql
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
When is REST from the database enough? @jameslcowanjun 3 '26 postgrest, postgresql
What is the difference between Postgres and PostgREST? @jameslcowanmay 19 '26 postgresql, postgrest
What is Drizzle, and why do teams treat the schema as a contract? @jameslcowanmay 12 '26 drizzle, typescript
What is PostgreSQL, and why do products still bet on it? @jameslcowanapr 29 '26 postgresql, product-engineering
What is the difference between Bun and Node? @jameslcowanapr 14 '26 bun, javascript
OpenClaw: What It Is and How to Get the Most Out of It @jameslcowanjun 5 '26 openclaw, javascript
Documentation That Scales: Constitution, Contracts, and Runbooks @jameslcowanjun 8 '26 documentation, markdown
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
Web Components as a Business Decision @jameslcowanjun 11 '26 web-components, javascript
Less JavaScript, More Leverage: Why I Ship With a 35KB Budget @jameslcowanjun 22 '26 javascript, performance
What is Supabase, and what are you actually buying? @jameslcowanmay 28 '26 supabase, postgresql
What is Neon, and how do preview databases change shipping? @jameslcowanmay 7 '26 neon, postgresql
Anthropic Trained Its Replacement @jameslcowanjun 9 '26 anthropic, ai
Karpathy Was Wrong: OpenClaw Still Outruns Its 5 Real Alternatives @jameslcowanjun 11 '26 openclaw, ai
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
Zero-Server Analytics: How I Replaced a SaaS Bill with Netlify Functions and GitHub @jameslcowanjun 8 '26 netlify, analytics
Static Site Generation: The Business Case for Pre-Rendered HTML @jameslcowanjun 14 '26 static-site-generation, performance

Recommended

What is TypeScript, and why do product teams still adopt it? @jameslcowanmar 31 '26 typescript, javascript
How do types go from the database to the client? @jameslcowanapr 8 '26 typescript, drizzle
What is React, and when is the weight worth it? @jameslcowanapr 22 '26 react, javascript
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
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
How This Site Works: Architecture for a One-Person Team @jameslcowanjun 8 '26 htmx, javascript
Progressive Enhancement with HTMX: Ship Fast, Degrade Gracefully @jameslcowanjun 8 '26 htmx, javascript
What is SQLite good for at the edge of a system? @jameslcowanjul 13 '26 sqlite, postgresql
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
When is REST from the database enough? @jameslcowanjun 3 '26 postgrest, postgresql
What is the difference between Postgres and PostgREST? @jameslcowanmay 19 '26 postgresql, postgrest
What is Drizzle, and why do teams treat the schema as a contract? @jameslcowanmay 12 '26 drizzle, typescript
What is PostgreSQL, and why do products still bet on it? @jameslcowanapr 29 '26 postgresql, product-engineering
What is the difference between Bun and Node? @jameslcowanapr 14 '26 bun, javascript
OpenClaw: What It Is and How to Get the Most Out of It @jameslcowanjun 5 '26 openclaw, javascript
Documentation That Scales: Constitution, Contracts, and Runbooks @jameslcowanjun 8 '26 documentation, markdown
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
Web Components as a Business Decision @jameslcowanjun 11 '26 web-components, javascript
Less JavaScript, More Leverage: Why I Ship With a 35KB Budget @jameslcowanjun 22 '26 javascript, performance
What is Supabase, and what are you actually buying? @jameslcowanmay 28 '26 supabase, postgresql
What is Neon, and how do preview databases change shipping? @jameslcowanmay 7 '26 neon, postgresql
Anthropic Trained Its Replacement @jameslcowanjun 9 '26 anthropic, ai
Karpathy Was Wrong: OpenClaw Still Outruns Its 5 Real Alternatives @jameslcowanjun 11 '26 openclaw, ai
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
Zero-Server Analytics: How I Replaced a SaaS Bill with Netlify Functions and GitHub @jameslcowanjun 8 '26 netlify, analytics
Static Site Generation: The Business Case for Pre-Rendered HTML @jameslcowanjun 14 '26 static-site-generation, performance