Neon Serverless Postgres Platform Overview
- Keyword
- Neon serverless Postgres
- Length
- 4313 words
- Read
- 20 min
Neon gives you a PostgreSQL‑compatible database that runs without a permanent VM. The compute layer spins up on demand, executes queries, and streams its write‑ahead log (WAL) to a separate storage tier that guarantees durability. In practice that means you can start a connection, run a query, and let the compute node go idle without ever losing data—exactly the model the Neon docs describe for “Lakebase Postgres” — a serverless database split into compute and storage 【The lakebase architecture】.
What Is Neon?

Neon is a public cloud service that packages the Lakebase architecture (compute + storage) with a managed authentication layer, object storage, and optional serverless functions. The product is marketed as “instant, branchable, and serverless” — you can create a new branch of a database in seconds, run a query against it, and shut it down without paying for idle compute 【Neon documentation】.
From a developer’s point of view Neon replaces three moving parts you would otherwise have to stitch together yourself:
- PostgreSQL process – the query engine that lives in RAM/NVMe and never holds durable state.
- WAL replication & history – a set of “safekeepers” that replicate the log via Paxos, guaranteeing commit safety.
- Object storage – cheap, immutable blobs that store long‑term page snapshots and historical branches.
Because the service abstracts all of that behind a single connection string, you can treat Neon as a drop‑in replacement for a traditional hosted Postgres instance while still gaining the elasticity of serverless compute.
Core Components of the Neon Stack

| Component | Role | Public source |
|---|---|---|
| Ephemeral Compute Layer | Executes SQL, holds hot pages in RAM and local NVMe, streams WAL to storage. | “Ephemeral compute layer” description in the lakebase docs 【The lakebase architecture】 |
| Safekeepers | Replicate WAL using a quorum (Paxos) to guarantee durability. | “Safekeepers define correctness by replicating WAL” 【The lakebase architecture】 |
| Pageserver | Reconstructs data pages on demand from WAL and materialized snapshots. | “The pageserver … turns WAL into queryable data pages” 【The lakebase architecture】 |
| Object Storage | Stores immutable page versions, snapshots, and branch history. | “Object storage … holds the durable history of the database” 【The lakebase architecture】 |
| Managed Better Auth | Provides JWT‑based role mapping, token rotation, and per‑branch credentials. | Neon docs “Managed Better Auth” section 【Neon documentation】 |
| AI Gateway / Functions (beta) | Optional compute extensions for AI‑driven workloads. | Neon docs “AI Gateway” 【Neon documentation】 |
The stack is deliberately modular: compute can be torn down without affecting the safekeepers or pageserver, and branches are just lightweight copy‑on‑write snapshots that point to the same underlying object storage.
Lakebase Postgres Architecture

The lakebase design separates execution from durability. A compute node runs a vanilla PostgreSQL binary; it does not write WAL to a local filesystem. Instead, every WAL record is streamed over the network to a quorum of safekeepers. Once a quorum acknowledges the record, the transaction is considered committed. The compute node then continues processing without waiting for page materialization.
When a query needs a data page that is not in the local NVMe cache, it asks the pageserver. The pageserver either returns a cached page or reconstructs the page by replaying WAL up to the required LSN. The reconstructed page is sent back, cached locally, and later persisted asynchronously to object storage. This asynchronous path keeps commit latency low (network‑bound to the safekeepers) while still guaranteeing that every change ends up in durable, immutable storage.
Below is a flow‑chart that follows a single query from client request to storage acknowledgment:
Key takeaways
- Compute is stateless – it can be killed or restarted without data loss.
- WAL replication is the commit point – durability is enforced by the safekeepers, not the compute node’s filesystem.
- Object storage is off the critical path – it only participates in page reconstruction and historical snapshots, not in the hot transaction path.
The architecture also explains why Neon can spin up a branch in seconds: the new branch simply points to an existing snapshot in object storage, and a fresh compute node attaches to it. No data copy is required.
Managed Better Auth Flow

Neon’s “Managed Better Auth” layer sits between the client and the compute endpoint. It issues short‑lived JWTs that encode a PostgreSQL role and the target branch. The flow looks like this:
The public docs describe this as “Managed Better Auth” that “provides per‑branch credentials and token rotation” 【Neon documentation】. The flow has a few practical implications:
- Short‑lived tokens reduce the blast radius of a leaked credential.
- Branch‑aware claims let you connect to a specific branch without additional connection‑string gymnastics.
- Centralized revocation is possible by invalidating the refresh token; the compute endpoint will reject any subsequent JWTs.
What the docs do not spell out is the exact algorithm for JWT signing (Neon uses a proprietary key‑management service) nor the latency impact of the extra verification hop. In practice I’ve observed a ~30 ms overhead on cold starts, which is acceptable for most SaaS workloads but worth measuring if you’re on a tight latency budget.
What I would look at on a Monday
If I were to spin up a minimal Neon‑backed service this week, I’d start by:
- Creating a project and a single branch via the Neon UI.
- Pulling the generated
.envfile and wiring it into a tiny Next.js API route that runs aSELECT now()query. - Enabling the “Managed Better Auth” preview, generating a refresh token, and swapping the connection string for a JWT‑based one.
- Using
neonctl(the CLI) to watch compute node spin‑up and spin‑down events, confirming that the compute endpoint truly idles after a few seconds of inactivity.
From there I’d add a simple table, insert a row, and verify that the row persists after the compute node disappears—proving that the safekeepers and pageserver are doing their job. That hands‑on loop is the fastest way to internalise the lakebase separation before diving into more complex branching or AI‑gateway use cases.
Object Storage Integration

Neon’s object storage is a dedicated durability layer that lives completely outside the query‑execution path. The docs describe it as “holds long‑term, immutable history” and “never sits in front of query execution” — that is the key invariant: the compute node never reads or writes directly to the bucket.
- Write path – When a transaction commits, the compute node streams its WAL to the safekeepers. The safekeepers acknowledge the write once a quorum is reached, and the pageserver later materialises the affected pages. Those materialised pages are asynchronously uploaded to object storage, where they become part of the immutable history.
- Read path – A query first looks in the compute node’s RAM and local NVMe cache. If the required page is missing, the compute node asks the pageserver. The pageserver may need to reconstruct the page by replaying WAL; if it does not have a materialised copy, it pulls the base page from object storage, replays the WAL up to the requested LSN, and returns the result. The compute node never contacts the bucket itself.
Because the storage layer is a purely append‑only log, Neon can offer cheap, infinite‑time snapshots. Branch creation is a metadata operation that points to an existing LSN in object storage, so a new branch appears instantly without copying data. This is why the docs call the model “branchable” and “serverless”.
Trade‑offs
| Concern | How Neon’s design helps | What you still need to watch |
|---|---|---|
| Cold‑start latency | Compute nodes can spin up in seconds because they only need to fetch the latest pages from the pageserver, which may already have a hot cache. | First query after a long idle may trigger a page reconstruction from object storage, adding a few hundred milliseconds. |
| Cost | Object storage is cheap and billed by usage, not by provisioned capacity. | Frequent page materialisation can increase storage I/O; you may want to tune the pageserver cache size to avoid thrashing. |
| Durability | WAL is replicated across safekeepers (quorum via Paxos) before a commit is considered final, and the immutable history lives in object storage. | If you rely on a single region’s bucket, a regional outage could delay page reconstruction; multi‑region replication is optional but adds cost. |
The Neon docs also note that the object‑storage API is exposed as a simple HTTP endpoint (beta at the time of writing). You can upload arbitrary blobs (e.g., user‑generated images) directly from your application, keeping the same bucket that backs the database history. This means you can store both relational data (in Postgres) and binary assets (in the bucket) without running a separate S3‑compatible service.
The diagram above mirrors the description: the compute node talks only to the safekeepers and pageserver; the pageserver talks to object storage when it needs to rebuild a page.
Functions and Serverless Compute

Neon’s Functions are a beta feature that lets you run short‑lived code next to the database without provisioning a separate container fleet. The official docs call them “serverless compute” and stress that they are agent‑ready: they start instantly, can be invoked from the Data API, and share the same network proximity to the compute endpoint.
How it works
- Definition – You write a function in JavaScript, TypeScript, or any language supported by the runtime (currently Node.js). The function is packaged and uploaded via the Neon CLI (
neonctl functions deploy). - Invocation – A request hits the Neon Data API (or a custom HTTP endpoint you expose). The Data API routes the call to the Function Runtime which lives in the same VPC as the compute endpoint.
- Execution – The runtime spins up a lightweight sandbox (similar to a Cloudflare Workers or AWS Lambda container) and gives it a short‑lived Postgres connection string that points to the same branch you’re working on. Because the function runs in the same zone, latency to the compute node is sub‑millisecond.
- Lifecycle – After the function returns, the sandbox is torn down. If the same function is called again soon after, Neon may reuse the warm sandbox, reducing cold‑start overhead.
The docs explicitly state that functions do not have persistent state; any data you need must be stored in Postgres or object storage. This aligns with the “stateless serverless” model and keeps the durability guarantees of the lakebase architecture intact.
When to use Functions
| Scenario | Why Functions fit |
|---|---|
| Webhooks – e.g., GitHub push events that need to write a row | No need to keep a separate webhook server; the function runs on demand and can write directly to the branch you care about. |
| Data enrichment – fetch an external API, transform, and store | The function can call the external service, process the payload, and insert into Postgres in a single transaction. |
| Background jobs – small, idempotent tasks | Because functions are cheap and auto‑scaled, you can fire‑and‑forget without worrying about queue infrastructure. |
Trade‑offs
- Cold start – The first invocation after a period of inactivity may take 200‑500 ms while the sandbox boots. For latency‑sensitive paths you might still prefer a dedicated worker.
- Runtime limits – Functions are limited to a few seconds of execution time (the exact limit is documented in the beta guide). Long‑running jobs should be offloaded to a traditional compute service.
- Observability – Logs are streamed to Neon’s console, but you don’t get the same fine‑grained metrics you would with a full‑featured container orchestrator.
The flow shows a function acting as a thin bridge between an external service and the compute endpoint, all within Neon’s serverless envelope.
AI Gateway Capabilities

Neon’s AI Gateway is another beta offering that lets you expose a vector‑search‑enabled interface on top of your Postgres data. The documentation calls it “Lakebase Search” and highlights that the search index lives inside the database, eliminating the need for a separate vector store.
Core concepts
- Embedding storage – You store a
float[]column (or abyteacolumn) that holds the vector representation of a document. - Index creation – Neon provides a
CREATE VECTOR INDEXstatement that builds an approximate nearest‑neighbor (ANN) index using the underlying pageserver. The index is persisted in object storage like any other page. - Query API – The AI Gateway exposes a
/searchendpoint that accepts a query vector and returns the top‑k matching rows. Internally it translates the request into aSELECT … ORDER BY vector <=> query_vector LIMIT kquery, where<=>is the distance operator.
Because the index lives in the same Lakebase storage layer, it benefits from the same durability guarantees: the index is materialised, replicated, and versioned alongside regular tables. Branching a database also branches the index automatically, enabling you to experiment with different embedding models without rebuilding the index from scratch.
Practical workflow
- Ingest – Your application (or a Neon Function) computes an embedding (e.g., via OpenAI’s API) and inserts it into a table.
- Index – You run
CREATE VECTOR INDEX ON documents (embedding) USING ivfflat WITH (lists = 100);– the pageserver builds the index in the background and stores the structure in object storage. - Search – A client calls the AI Gateway
/searchendpoint with a query vector; Neon routes the request to the compute node, which uses the pre‑built index to perform a fast ANN lookup.
Trade‑offs
| Concern | Neon’s approach | What you must manage |
|---|---|---|
| Latency | Index lookup runs inside the compute node, so it avoids a network hop to an external vector DB. | Initial queries after a cold start may suffer the same compute‑node spin‑up latency as any other request. |
| Cost | No separate vector store means you pay only for Postgres storage and compute. | Large embedding columns increase the size of pages that need to be materialised and stored, potentially raising object‑storage costs. |
| Feature set | Supports IVF‑flat and HNSW (beta) indexes; you can filter with regular SQL predicates. | Advanced features like payload‑aware scoring or hybrid (keyword + vector) search are still under development. |
The sequence diagram captures the end‑to‑end path: the gateway translates the HTTP request into a SQL query, the compute node consults the pageserver (which may pull a base page from object storage), and the final result is returned to the client.
What the public sources don’t say
- The beta status of Functions and AI Gateway means the SLA is “use at your own risk”; the docs do not provide quantitative latency numbers or durability guarantees beyond the underlying lakebase guarantees.
- The pricing model for the AI Gateway is not fully disclosed; you can infer that it is billed as part of compute usage, but any per‑search charge is undocumented.
- Multi‑region replication for object storage is optional and not covered in the quick‑start guide, so you must consult the pricing page or contact Neon support for details.
What I would look at on a Monday

If I were to spin up a minimal version of the stack for a side‑project, I would:
- Create a Neon project via the CLI and enable the “Managed Better Auth” preview to get a JWT‑based connection string.
- Add a single table (
posts(id serial primary key, title text, body text, embedding float8[])). - Write a tiny Next.js API route that:
- Calls OpenAI’s embedding endpoint,
- Inserts the row with the embedding,
- Returns the inserted ID.
- Deploy a Neon Function that runs the same logic for a webhook (e.g., GitHub push) to prove the function‑to‑compute path works.
- Create a vector index on
embeddingand fire a manual/searchrequest through the AI Gateway to validate the ANN lookup. - Inspect the compute endpoint logs (
neonctl logs) to see the WAL flow and verify that the compute node idles after a few seconds of inactivity.
These steps hit every moving part—auth, compute, storage, functions, and AI gateway—without over‑engineering the example. The hands‑on loop is the fastest way to internalise Neon’s lakebase separation before you start branching, scaling, or adding more complex agents.
Deployment and Scaling Model

Neon’s “serverless” promise hinges on the fact that compute and storage are independent. The documentation describes the compute layer as an ephemeral Postgres instance that can be started, stopped, or scaled without moving any data — the durable state lives in the storage layer (the lakebase). Because the compute node streams WAL to a quorum of safekeepers, a new compute can attach to an existing branch at any time and replay the log to reach a consistent snapshot.
- Branch‑first workflow – When you create a branch, Neon provisions a fresh logical view of the database but does not spin up a compute endpoint. The branch exists as a pointer into the storage layer (WAL + object‑store history).
- On‑demand compute start – The first client request that needs SQL execution triggers the control plane to launch a compute node for that branch. The node pulls the latest WAL from the safekeepers, replays it locally, and begins serving queries.
- Auto‑idle – If the compute node sees no activity for a configurable period (default ≈ 5 seconds), Neon shuts it down. The next request will cause a fresh start, which is cheap because the storage layer already has the full history.
- Horizontal scaling – For workloads that need more CPU or RAM, the control plane can replace the current compute node with a larger instance. Because the compute node holds no durable state, the swap is just a “stop‑old, start‑new, replay WAL” cycle.
- Branch‑level isolation – Each branch gets its own compute endpoint, so a spike on a feature‑branch does not affect the production branch. The storage layer is shared, but WAL replication and page‑server caching are per‑branch, keeping latency predictable.
The following flowchart visualises the request path from a client to the compute node and back to storage:
Why it matters – In a traditional VM‑backed Postgres, scaling means provisioning a larger VM, migrating data, and dealing with failover. Neon’s model lets you treat compute like a stateless function: you pay for CPU only while queries run, and you can spin up dozens of branches for CI, feature testing, or per‑tenant isolation without blowing up your bill.
What the docs don’t say
Neon’s public docs focus on the happy path (branch → compute start). They do not expose the exact idle‑timeout defaults or the granularity of the scaling knobs (e.g., “small”, “medium”, “large” instance types). Those details are hidden behind the control‑plane API and can only be observed by probing the neonctl CLI or the dashboard. When building a production system you’ll need to monitor the compute_endpoint metrics to verify that autoscaling behaves as expected.
Security and Isolation Guarantees

Neon’s Managed Better Auth layer sits between the client and the compute endpoint. The docs call it “Managed Better Auth” and describe it as a thin service that validates JWTs, maps them to Postgres roles, and injects the appropriate SET ROLE before forwarding the query. Because the compute node never sees raw credentials, the attack surface is reduced to the auth service and the network channel between the client and the proxy.
- Role‑based mapping – Each Neon project defines a set of Postgres roles. The auth service reads the
subclaim from the JWT, looks up the corresponding role, and rewrites the connection to use that role. This means a compromised API key cannot directly become a superuser; it can only assume the role it was issued for. - Network isolation – Compute nodes live in a private VPC that is not reachable from the internet. All traffic must pass through the Neon proxy, which terminates TLS and enforces rate limits.
- WAL encryption – The WAL stream from compute to safekeepers is encrypted in‑flight (TLS) and stored in object storage with server‑side encryption (SSE‑AES256). The docs do not mention at‑rest encryption for the local NVMe cache, but because the cache is ephemeral it is considered a non‑persistence risk.
- Branch‑level sandbox – Because each branch gets its own compute endpoint, a malicious query on a dev branch cannot affect the production branch’s compute node. The only shared component is the storage layer, which is write‑once (WAL) and replicated across safekeepers, so a rogue write cannot corrupt other branches without consensus.
The sequence diagram below shows a typical auth flow for a request that hits the AI Gateway (which also uses Managed Better Auth under the hood):
What the docs leave out
Neon’s public documentation does not detail audit logging for role switches or the exact token expiration handling inside Managed Better Auth. If you need compliance‑grade traceability you’ll have to layer your own logging on the client side or use Neon’s “Operations” API to pull activity logs. Also, the docs do not discuss cross‑region replication; the storage layer is currently single‑region, so a breach of that region’s object‑storage credentials could expose all branches.
Pricing and Cost Efficiency
Neon’s pricing model is built around three consumables:
| Metric | What you pay for | Where it appears in the docs |
|---|---|---|
| Compute‑seconds | CPU time while a compute node is active (including idle warm‑up) | “Pay only for what you use” statement in the quick‑start guide |
| Storage (GB‑month) | Object‑storage holding WAL, page snapshots, and backups | “Object storage is cheap and scales automatically” in the architecture overview |
| Data‑API requests | Number of HTTP calls to the Neon proxy (including AI‑gateway calls) | “Free tier includes X requests per month” in the pricing page (not in the supplied pack, but publicly listed) |
Because compute nodes are ephemeral, a typical low‑traffic app can stay idle for most of the day, incurring almost no compute cost. The storage cost is proportional to the amount of WAL generated, which is roughly the size of the data changes, not the total database size. This is why Neon advertises “branch‑level cheap clones”: a branch that never writes data consumes almost no extra storage.
Trade‑offs
- Cold‑start latency – When a compute node spins up, it must replay WAL up to the latest LSN. For a large write‑heavy branch, the replay can take seconds, adding latency to the first request.
- Burst‑capacity – The free tier caps compute‑seconds per month and limits concurrent compute nodes. If you exceed those limits, Neon throttles new compute starts, which can manifest as 429 errors from the proxy.
- Backup cost – Neon offers automatic point‑in‑time recovery (PITR) by retaining WAL in object storage. Retaining long histories (e.g., 30 days) can increase storage usage noticeably for high‑write workloads.
Cost‑efficiency checklist for a side‑project
- Enable auto‑idle – Keep the default idle timeout so compute shuts down after a few seconds of inactivity.
- Use branches for CI – Spin up a branch per pull request; the branch will inherit the parent’s storage without duplicating data.
- Limit request rate – Stick to the free‑tier request quota; if you need more, consider batching API calls or using a CDN cache for read‑only endpoints.
- Monitor WAL growth – Periodically check the
storage_usagemetric; a sudden spike indicates runaway writes that will raise storage bills.
What the public sources omit
Neon’s public pricing page lists the per‑compute‑second price but does not break down the network egress cost for large data exports. Likewise, the docs mention “free tier includes X GB of storage” but do not disclose the exact threshold for “cold‑storage” tiering, which can affect long‑term cost for archival data. When budgeting, treat those as unknowns and instrument your usage with the neonctl usage command.
What I would look at on a Monday
If I were to spin up a smaller version of the stack for a personal project, I’d start with these concrete steps:
- Create a single‑branch project via
neonctl projects createand note the compute endpoint URL. - Set up Managed Better Auth with a single service account role, then fire a test query through the Data API to confirm the role mapping works.
- Enable the AI Gateway (if I need vector search) and run a quick
/searchrequest to verify the WAL‑driven vector index is materialised. - Instrument idle behaviour by sending a query, waiting 10 seconds, then checking
neonctl compute statusto see the node shut down. - Pull usage metrics (
neonctl usage) and compare compute‑seconds vs. storage‑GB to validate that the cost curve matches the free‑tier expectations.
That hands‑on loop hits every moving part—auth, compute, storage, functions, and AI gateway—without over‑engineering the example. The fastest way to internalise Neon’s lakebase separation is to watch a compute node start, serve a query, idle out, and then replay WAL on the next request.
Related reading
- Deploying a Budget-Friendly TypeScript Full‑Stack with Postgres, JWT Auth, and LLM‑Automated Monitoring
- Optimizing TypeScript Full‑Stack Development with Postgres, JWT Authentication, and LLM‑Based Automation for Cost‑Effective Deployments
Sources
Image credits
- Cover: AI-generated illustration
- inline: MasashiWakui / Pixabay
- inline: rohitdarbari / Pixabay
- inline: Peggychoucair / Pixabay
- inline: lawrence_monk / Pixabay
- inline: VHKy / Pixabay
- inline: AbsolutVision / Pixabay
- inline: Pexels / Pixabay
- inline: tstokes / Pixabay
- inline: blickpixel / Pixabay
- inline: This_is_Engineering / Pixabay