A Next.js app needs somewhere to keep its data, and for most teams that's PostgreSQL. You can run your own Postgres plus an ORM, or use a Postgres backend-as-a-service that gives you a REST API, auth, file storage and realtime on top of the database. This guide shows the second route with the App Router and WoWSQL's TypeScript SDK, @wowsql/sdk on npm, and explains which key belongs on the server and which in the browser.
Key facts
- Package:
@wowsql/sdkversion 3.10.0, installed withnpm install @wowsql/sdk. Licence: Elastic License 2.0.- Client:
new WowSQLClient({ projectUrl, apiKey }), thenclient.table('posts').select('*').get().- Under the hood: the SDK sends standard PostgREST requests to
https://<slug>.wowsqlconnect.com/rest/v1.- Keys: the anon key (
wowsql_anon_…) respects Row Level Security and can go in the browser. The service key (wowsql_service_…) bypasses it and stays on the server.- Also in the SDK:
ProjectAuthClientfor auth,WowSQLStoragefor files andclient.realtimefor live changes.- Regions: Mumbai (the default) and US East 1. Free plan, then $25 or $99 a month.
Two ways to back Next.js with Postgres
Direct connection. A server component or route handler opens a Postgres connection through a driver or an ORM such as Prisma or Drizzle. You get full SQL. You also own migrations, connection limits in serverless functions, and you build auth, uploads and change notifications yourself.
Postgres over HTTP. A backend-as-a-service puts PostgREST, auth, storage and realtime in front of the database. Your Next.js code makes HTTPS calls, which suit serverless and edge runtimes. That's the route here.
Vercel no longer offers its own Postgres. Its docs (checked 21 October 2026) say existing Vercel Postgres databases were moved to Neon in December 2024 and that new projects should add a Postgres integration from the Vercel Marketplace. So whatever you deploy on, you're choosing an outside Postgres provider.
1. Create a project and a table
Create a free project at app.wowsql.com, choosing Mumbai or US East 1. In the SQL editor:
create table public.posts (
id uuid primary key default gen_random_uuid(),
title text not null,
body text,
published boolean not null default false,
created_at timestamptz not null default now()
);
Use a UUID primary key. WoWSQL's docs say raw SQL table creation doesn't accept SERIAL PRIMARY KEY. Then copy the project slug and both keys from Settings → API.
2. Install the SDK and set environment variables
npm install @wowsql/sdk
In .env.local:
WOWSQL_PROJECT_URL=myproject
WOWSQL_SERVICE_KEY=wowsql_service_your_key
NEXT_PUBLIC_WOWSQL_PROJECT_URL=myproject
NEXT_PUBLIC_WOWSQL_ANON_KEY=wowsql_anon_your_key
Next.js only sends variables starting with NEXT_PUBLIC_ to the browser. So the service key, without that prefix, never leaves the server. Never add the prefix to it.
3. A server-only client
Create lib/wowsql-server.ts:
import 'server-only';
import WowSQLClient from '@wowsql/sdk';
export const db = new WowSQLClient({
projectUrl: process.env.WOWSQL_PROJECT_URL!,
apiKey: process.env.WOWSQL_SERVICE_KEY!,
});
The server-only import (from the npm package of the same name) makes the build fail if a client component ever imports this file. That stops the service key from ending up in a browser bundle.
4. Read data in a server component
// app/posts/page.tsx
import { db } from '@/lib/wowsql-server';
export default async function PostsPage() {
const { data } = await db.table('posts')
.select('id', 'title', 'created_at')
.eq('published', true)
.order('created_at', 'desc')
.limit(20)
.get();
return (
<ul>
{data.map((p) => <li key={p.id}>{p.title}</li>)}
</ul>
);
}
This runs on the server, so the key is never exposed. The query builder also has first(), single(), count() and paginate(page, perPage) for list pages.
5. Write data with a server action
// app/posts/new/actions.ts
'use server';
import { revalidatePath } from 'next/cache';
import { db } from '@/lib/wowsql-server';
export async function createPost(formData: FormData) {
const title = String(formData.get('title') ?? '').trim();
if (!title) return;
await db.table('posts').insert({ title, body: String(formData.get('body') ?? '') });
revalidatePath('/posts');
}
Point a <form action={createPost}> at it. Because the service key bypasses Row Level Security, the action itself has to check who is allowed to write. Validate the input and check the user's session first (see the next section).
Updates and deletes go by primary key: db.table('posts').update(id, { published: true }) and db.table('posts').delete(id).
6. Sign users in
import { ProjectAuthClient } from '@wowsql/sdk';
const auth = new ProjectAuthClient({
projectUrl: process.env.NEXT_PUBLIC_WOWSQL_PROJECT_URL!,
apiKey: process.env.NEXT_PUBLIC_WOWSQL_ANON_KEY!,
});
const login = await auth.signIn({ email, password });
const token = login.session?.accessToken;
The auth client also covers sign-up, OAuth through an authorization URL, TOTP two-factor, and, since 3.10.0, anonymous sign-in and identity linking once you enable them in the project's auth settings. To check a session in a server action, call auth.getUser(accessToken).
Tokens are held in memory by default. You can pass a storage option with your own token store, for example one that writes an httpOnly cookie through a route handler.
About Row Level Security. In 3.10.0, WowSQLClient sends the API key you give it on table requests, and the docs don't yet show how to run a table query as the signed-in user. For per-user rules such as "authors edit only their own posts", do the writes in server actions that verify the user first, as in step 5, or ask us how to set it up on your plan.
7. Live updates in a client component
'use client';
import { useEffect, useState } from 'react';
import WowSQLClient from '@wowsql/sdk';
const client = new WowSQLClient({
projectUrl: process.env.NEXT_PUBLIC_WOWSQL_PROJECT_URL!,
apiKey: process.env.NEXT_PUBLIC_WOWSQL_ANON_KEY!,
});
export function NewPostsBadge() {
const [count, setCount] = useState(0);
useEffect(() => {
const sub = client.realtime.subscribe(
{ schema: 'public', table: 'posts', event: 'INSERT' },
() => setCount((c) => c + 1),
);
return () => { sub.unsubscribe(); };
}, []);
return count ? <span>{count} new posts</span> : null;
}
Enable realtime for the table first, from the dashboard or with POST /realtime/v1/enable. Browsers can't set WebSocket headers, so the anon key travels as a query parameter, which is another reason never to use the service key here. Payloads are capped at 64 KiB.
8. Files
WowSQLStorage handles uploads: storage.upload('avatars', file, 'users/me.png') and storage.getPublicUrl('avatars', 'users/me.png'). Run uploads from a server action when the bucket is private, and add your site's origin to the project's CORS allowlist for browser calls.
Choosing a setup
- Prisma or Drizzle on a Marketplace Postgres suits teams that want full SQL in TypeScript and are happy to add their own auth and storage.
- A Postgres BaaS suits teams that want auth, files and realtime ready-made, with plain HTTPS calls from serverless functions.
WoWSQL fits the second case when you want your database in Mumbai or US East 1 and a vendor based in India. It's an Indian company that is DPIIT-recognised and part of NVIDIA Inception.
Related reading
- Indian Supabase alternative: Postgres BaaS in Mumbai
- Supabase pricing in India
- Flutter Postgres backend with the Dart SDK
- Postgres MCP server: local vs hosted
- TypeScript SDK docs
FAQ
Can Next.js connect directly to PostgreSQL?
Yes, from server components, route handlers and server actions, through a driver or an ORM. Never from client components, because the database credentials would ship to the browser.
Which WoWSQL key goes in a Next.js app?
The anon key, in a NEXT_PUBLIC_ variable, for client components. The service key goes in a server-only variable and is used only in server code.
Does @wowsql/sdk work in server components and server actions?
Yes. It makes HTTPS calls to your project's PostgREST endpoint, so it runs anywhere your server code runs. Put it behind a server-only module when you use the service key.
What replaced Vercel Postgres?
Vercel's docs say Vercel Postgres is no longer available, that existing databases moved to Neon in December 2024, and that new projects should use a Postgres integration from the Vercel Marketplace.
Is there a free plan for a Next.js side project?
Yes. WoWSQL's free plan includes one project with a 256 MB database, auth, realtime and the REST API, with no credit card needed. Paid plans are $25 and $99 a month.