tutorial··5 min read·WoWSQL Team

Instant REST API for Postgres: A Practical Guide

An instant REST API for Postgres, explained: how PostgREST maps tables to URLs, filters, writes, API keys and RLS, with curl and TypeScript examples.

You can put a REST API in front of a Postgres database without writing a single route handler. A tool called PostgREST reads your schema and turns every table and view into an HTTP endpoint, with filtering, sorting, pagination and writes handled through the URL. This guide explains how that works, what you still have to think about (keys, permissions, aggregates), and how to get an instant REST API for Postgres on WoWSQL with curl and the TypeScript SDK.

Key facts

  • What does the work: PostgREST, a standalone web server that turns a PostgreSQL database into a RESTful API. Its stable docs were at version 16 when we checked on 22 October 2026.
  • On WoWSQL: every table gets endpoints at https://<slug>.wowsqlconnect.com/rest/v1/<table> as soon as you create it.
  • Keys: the anon key (wowsql_anon_…) respects Row Level Security and can be used client-side. The service key (wowsql_service_…) bypasses it and stays on a server.
  • SDK: npm install @wowsql/sdk, then new WowSQLClient({ projectUrl, apiKey }).table('todos').select('*').get().
  • Plans and regions: a free plan, then $25 or $99 a month. Projects run in Mumbai or US East 1.

What "instant REST API" actually means

With a hand-written API, every new table means a new route, query and tests. An auto-generated API skips that. The API layer looks at the database itself, so when you add a table or a column, the endpoint exists right away.

PostgREST is the most widely used tool for this in the Postgres world. Its own docs describe the idea as treating the database as the single source of truth: the tables, constraints and permissions you define in SQL decide what the API exposes and who can do what. Supabase's Data API is built on it too; its docs (checked 22 October 2026) say the REST interface is "automatically reflected from your database's schema".

WoWSQL uses standard PostgREST, so the URL syntax below works the same way you'd see it in the PostgREST docs.

Three ways to get one

Run PostgREST yourself. Download the binary or Docker image, point it at your database with a connection string, and configure a database role for anonymous requests. You own the server, TLS, upgrades and auth.

Use a Postgres backend-as-a-service. A BaaS hosts PostgREST for you, next to auth, file storage and realtime, and hands you an API URL and keys. Our comparison of Supabase alternatives covers several options.

Write your own API. Express, FastAPI or Next.js route handlers with an ORM. More code, more control. Worth it when your endpoints don't map neatly onto tables.

The rest of this guide uses the second route on WoWSQL.

Step 1: create a table

Sign up for a free WoWSQL project, pick Mumbai or US East 1, and run this in the SQL editor:

create table public.todos (
  id uuid primary key default gen_random_uuid(),
  title text not null,
  done boolean not null default false,
  created_at timestamptz not null default now()
);

Then copy your project slug and both API keys from the Connect menu on the project overview, or from Settings → API.

Step 2: read rows with curl

The endpoint is already live. Reading is a plain GET with your key in the apikey header:

curl "https://myproject.wowsqlconnect.com/rest/v1/todos?select=id,title,done&done=eq.false&order=created_at.desc&limit=10" \
  -H "apikey: wowsql_anon_your_key"

Each part of the query string does one job:

  • select=id,title,done picks columns.
  • done=eq.false is a filter: column, operator, value.
  • order=created_at.desc sorts.
  • limit=10 (with offset=20 for later pages) paginates.

The common operators are eq, neq, gt, gte, lt, lte, like, ilike (case-insensitive), is.null, not.is.null, in.(a,b,c) and not.in.(a,b). For example, title=ilike.*invoice* finds titles containing "invoice" in any case.

Step 3: write, update and delete

Writes use the HTTP verb you'd expect. Add Prefer: return=representation to get the changed row back in the response.

# Insert
curl -X POST "https://myproject.wowsqlconnect.com/rest/v1/todos" \
  -H "apikey: wowsql_service_your_key" \
  -H "Content-Type: application/json" \
  -H "Prefer: return=representation" \
  -d '{"title": "Ship the REST guide"}'

# Update rows that match a filter
curl -X PATCH "https://myproject.wowsqlconnect.com/rest/v1/todos?id=eq.<uuid>" \
  -H "apikey: wowsql_service_your_key" \
  -H "Content-Type: application/json" \
  -d '{"done": true}'

# Delete rows that match a filter
curl -X DELETE "https://myproject.wowsqlconnect.com/rest/v1/todos?id=eq.<uuid>" \
  -H "apikey: wowsql_service_your_key"

Always include a filter on PATCH and DELETE. Without one, you're asking to change every row the key is allowed to touch.

One thing to watch: WoWSQL also has a control-plane API on api.wowsql.com that uses your account login token, not project keys. In that API, DELETE /api/v1/db/tables/{table} drops the whole table. For deleting rows, use the /rest/v1 call above.

Step 4: the same thing in TypeScript

If you'd rather not build URLs by hand, the SDK sends the same PostgREST requests for you:

import WowSQLClient from '@wowsql/sdk';

const client = new WowSQLClient({
  projectUrl: 'myproject', // → https://myproject.wowsqlconnect.com
  apiKey: process.env.WOWSQL_SERVICE_KEY!,
});

const { data } = await client.table('todos')
  .select('id', 'title', 'done')
  .eq('done', false)
  .order('created_at', 'desc')
  .limit(10)
  .get();

await client.table('todos').create({ title: 'Write tests' });
await client.table('todos').update(id, { done: true });
await client.table('todos').delete(id);

The TypeScript SDK docs list the rest: first(), getById(), in(), between(), typed tables with generics and a WowSQLError class for error handling. For a full app example, see the Next.js Postgres backend guide. Mobile developers can follow the Flutter Postgres backend guide, which uses the Dart SDK against the same endpoints.

Keys and permissions: the part people skip

An instant API is only as safe as the key you hand out.

  • The anon key respects Row Level Security, so it's the one meant for browsers and mobile apps. Turn on RLS for every table it can reach and write policies for what anonymous callers may read or write. A table with RLS off is open to anyone holding the anon key.
  • The service key bypasses RLS. Keep it in server environment variables only, and check who the user is in your own code before a write.

Per-user rules, such as "users can only see their own todos", need the request to run as the signed-in user. The current SDK docs don't yet show how to send a user's session on table requests, so for now handle per-user writes in server code that verifies the user first, or ask us how to set it up on your plan.

What PostgREST doesn't do for you

  • Aggregates. /rest/v1 doesn't run GROUP BY or HAVING, so COUNT(*) in a select won't be evaluated. Create a view (which gets its own endpoint) or a Postgres function and call it instead. WoWSQL's docs recommend exactly that.
  • Multi-step business logic. If one request must touch several tables in one transaction, put it in a Postgres function.

When an instant API is the right call

It fits well when your app is mostly create, read, update and delete over a clear schema: dashboards, internal tools, MVPs, mobile backends and AI agents that query data. It fits less well when the API is a public product in its own right with versioning promises, or when most endpoints are workflows rather than tables.

If you're building in India, running the API in Mumbai keeps requests close to your users; our managed Postgres in India guide goes into the region side. AI tools can use the same project through WoWSQL's hosted MCP server, covered in the Postgres MCP server guide.

FAQ

What is the fastest way to get a REST API for Postgres?

Use a hosted service that runs PostgREST for you. On WoWSQL you create a table and its endpoint at /rest/v1/<table> is live straight away, with no server code.

Is PostgREST secure enough for production?

It enforces whatever your database enforces. That means Row Level Security policies and role permissions decide access. With RLS on and the service key kept on the server, it's a sound setup. With RLS off and the anon key public, anyone can read and change that table.

Can I filter, sort and paginate through the URL?

Yes. Filters look like status=eq.active or age=gte.18, sorting is order=created_at.desc, and paging uses limit and offset. Pick columns with select=id,name.

Does an auto-generated API support joins and aggregates?

Aggregates such as COUNT(*) with GROUP BY aren't run on /rest/v1. Define a view or a Postgres function and call that endpoint instead. For anything involving several tables in one transaction, a function is the safer choice.

How much does WoWSQL cost for this?

There's a free plan with REST APIs included. Paid plans are $25 and $99 a month; see the pricing page for current limits.