A serverless SQL database for edge functions scales to zero, speaks HTTP, and places data near the function runtime. Learn how it works, compare providers, and set up Telnyx SQL Database with TypeScript.

A serverless SQL database for edge functions is a relational database that provisions on demand, scales to zero when idle, is reachable over HTTP rather than a long-lived TCP socket, and places its data close to where the function runtime executes. The last part is what separates it from a normal managed database with a serverless price tag.
The distinction matters because edge functions run in constrained runtimes distributed across many locations. They are optimized to start in single-digit milliseconds and to run near the request. A database designed for a long-lived application server assumes the opposite: a stable process, a connection pool held open for hours, and a network path measured in single-digit milliseconds because the app server sits in the same datacenter.
Pair the two naively and you get a distributed frontend bolted onto a single-region backend. The function starts fast, then waits. If you want the foundational concept first, our serverless database guide covers the scaling and billing model before you get to placement.
Three things define the category:
pg over raw TCP, because the runtime will not allow it.Run your database where your functions runTelnyx Edge Compute and SQL Databases live on the same owned network. No cross-vendor hops, no per-query latency floor. Explore Edge Compute or read the SQL Database docs.
Start building freeTwo separate failure modes get conflated. Solving one does not solve the other.
PostgreSQL implements a process per user client and server model, where every client connection spawns a dedicated backend process. That design is why connection pooling exists. Reusing a socket across thousands of requests amortizes an expensive setup.
Edge runtimes cannot participate. Vercel's Edge runtime is built on V8 isolates that expose a subset of Web APIs and no filesystem. Cloudflare Workers, Deno Deploy, and Supabase Edge Functions land in the same place. An invocation cannot hold a socket open for the next one.
Vendors answered with HTTP drivers. The Neon serverless driver queries Postgres over HTTP or WebSockets instead of TCP, and PlanetScale supports the same driver on platforms where TCP pooling is not viable. This works. It is a real fix for a real problem.
An HTTP driver changes the transport. It does not move the data.
Network latency has a floor set by physics. Light in fiber travels at roughly two thirds of its vacuum speed, which puts the round trip from New York to Sydney at about 160 milliseconds along an idealized great-circle path. Real routes run higher once you add routing, queuing, and processing delay at every hop.
Now put a function in Sydney and a Postgres primary in Virginia. Your function executes in 5ms and waits 200ms. Run an ORM that issues four sequential queries to assemble one response and you have spent nearly a second before the first byte leaves. This is not a code optimization problem. Regional serverless functions avoid it by sitting next to the database on purpose, which is a sound trade and also the thing edge deployment was supposed to remove.
Supabase says this out loud. Its documentation on Edge Functions tells you to treat Postgres as a remote pooled service and to pin execution to the database region for data-heavy work. That is correct engineering advice, and it is also an admission that the compute moved and the data did not.
The structural fix is to stop treating compute and storage as two purchases from two vendors with a public internet segment between them.
Telnyx Edge Compute runs functions as containers on infrastructure Telnyx owns, at edge sites inside carrier facilities rather than generic cloud availability zones. Telnyx SQL Databases are SQLite databases that live on that same platform. You declare one in your function manifest and it resolves as env.DB at runtime, with credentials injected by the platform rather than written into your code.
Here is the honest architecture, because the details determine whether this fits your workload.
Each SQL database is served by one primary, and statements run one at a time against it. There are no regional read replicas. The gain is not that a copy of your data sits in every city. The gain is that the function runtime, the SQL layer, the object storage, the GPU inference, and the telephony network are all on one owned backbone under one bill, so the path between your handler and your rows is short and does not leave that network.
The consistency story is simpler as a result. A row written on the request path is immediately visible to the next CLI query or REST call, because every access path hits the same primary. There is no replica lag to reason about, no read-your-writes edge case to defend against, and no session token to thread through your code.
When you need true zero-hop access, the platform has a second surface. Stateful edge functions built on Stateful Actors, currently in beta, embed a private SQLite database inside each actor instance, reached synchronously through ctx.storage.sql. That database cannot be queried from outside its actor and cannot join across instances, which is the trade you make for having no network between code and data.
| Provider | Engine | Data placement | Edge access model | Best fit |
|---|---|---|---|---|
| Telnyx SQL Database | SQLite | One primary on Telnyx network | env.DB binding, REST, CLI | Compute, SQL, and telephony on one platform |
| Cloudflare D1 | SQLite | Primary plus read replicas | Worker binding, REST via control plane | Read-heavy apps already on Workers |
| Neon | PostgreSQL | Single primary region | HTTP and WebSocket driver | Teams committed to full Postgres |
| Turso | libSQL | Cloud primary plus local replicas | HTTP client, embedded replica file | Servers and devices with a filesystem |
| PlanetScale | MySQL on Vitess, PostgreSQL | Regional primary, read replicas | Neon serverless driver, Hyperdrive | Large scale and schema migrations |
| Supabase | PostgreSQL | Single project region | Pooled connection or HTTP driver | Bundled backend with auth and storage |
Vendor limits and pricing move quickly. Every figure below reflects each provider's published documentation as of August 2026, and it is worth confirming against their live docs before you commit.
Cloudflare D1 is the incumbent and deserves the position. Read replication made the read-heavy case stronger, and the free tier is hard to beat. The constraints are published: 10 GB per database on the paid plan, 100 columns per table, 100 bound parameters per query, and single-threaded query processing, so a workload averaging 1ms per query tops out near 1,000 queries per second. Binding access is a Workers feature. A REST API exists, but it routes through Cloudflare's control plane and costs meaningfully more latency. If those limits are what brought you here, our roundup of Cloudflare D1 alternatives goes deeper on migration paths.
Neon gives you real PostgreSQL with extensions, branching, and scale-to-zero, plus the driver that made edge Postgres viable at all. Its database still lives in one primary region, so an edge function in another hemisphere pays the distance.
Turso is architecturally the closest thing on this list to local data access, and it deserves a fair hearing. Embedded replicas keep a SQLite file inside your application process and serve reads in microseconds. One caveat matters for this use case, and Turso documents it: serverless environments without a filesystem cannot use embedded replicas. That rules out the isolate-based edge runtimes this article focuses on. From a Worker or a Vercel edge function you are calling Turso's cloud primary over HTTP like any other remote database.
PlanetScale brings Vitess-grade horizontal scaling and the best schema migration workflow in the category. It is not an edge product. Its own documentation routes Cloudflare Workers users to Hyperdrive and Vercel users to PgBouncer, which tells you where the data is expected to live.
Supabase is a backend, not just a database, and the bundle is genuinely convenient. Its edge functions and its Postgres instance are not co-located, so the round trip persists inside a single vendor.
Five steps, start to finish. You need the telnyx-edge CLI authenticated and Node.js installed.
The response carries a UUID. That id is the only durable handle, since names are not resolution keys. A new database starts at status: "pending" and takes roughly 2 to 11 seconds to provision. Poll until status reads provision_ok rather than sleeping a fixed interval, because SQL sent to a pending database returns a 409.
Schema can exist before any code does. The --remote flag is required, as there is no local emulation.
Add an index on anything you filter or order by. Statements against one database run one at a time, so a slow scan delays everything queued behind it.
Use execute for one-off statements and inspection. For schema changes you intend to keep and replay on another database, use migrations instead: numbered .sql files applied in order with telnyx-edge storage sqldb migrations, tracked by a table inside the database itself.
Scaffold a function first, then add the storage block to the manifest.
name = "links-api"
main = "src/index.ts"
compatibility_date = "2026-05-14"
[storage.sqldb.DB]
id = "550e8400-e29b-41d4-a716-446655440000"
[edge_compute]
func_id = "<written by new-func>"
func_name = "links-api"The block name, DB here, becomes env.DB in your code. Bind by id, not by name. Then generate types, which runs offline and needs no authentication.
One thing trips people up. The binding lives on the env you import from @telnyx/edge-runtime, not on the second argument to fetch(req, env). Reading it off that argument compiles cleanly and is undefined at runtime.
Note the shape. prepare() is synchronous and returns a statement, .bind() returns a new statement rather than mutating the original, and the terminal calls are async. Always bind request values with ? placeholders instead of concatenating SQL.
ship prints the function host. Call it, then read the same rows back from your terminal to confirm both paths reach the same primary.
Telnyx publishes typical figures to set expectations. Under typical conditions, a warm simple statement runs about a 10ms round trip, and a 5,000-row read takes roughly 160ms. Treat both as guidance rather than a guarantee, since query shape, index coverage, and result size all move the number. Plan around the documented ceilings too: 1 GiB per database, 2 MiB per bound value, and a result set capped near 4 MiB per statement. Page through large reads rather than selecting them whole, and keep images and archives in object storage with the key in SQL.
Neither answer is universally right, and the honest framing helps you more than a pitch.
Reach for SQL on the same network as your compute when your traffic is globally distributed and latency sensitive, your workload is read-heavy with modest write concurrency, your dataset fits comfortably under a gigabyte per database, and you want one vendor for compute, storage, and observability. Real-time voice and agent workloads fit this profile especially well, because every avoidable hop competes with the inference budget for the same conversational turn.
Stay with a centralized serverless database when you need PostgreSQL extensions, stored procedures, or a rich type system, your writes are heavily transactional and concurrent, your dataset runs to hundreds of gigabytes, or your team already has migration tooling, dashboards, and runbooks built around Postgres. SQLite has an honest published guide to its own limits, including one writer per database at a time and a recommendation against direct simultaneous access over a network. Read it before you commit either way.
Factor in data residency early, not late. Where your rows physically sit is a compliance question as much as a latency one. Under GDPR and similar regimes, moving personal data across borders is a decision your legal team needs to sign off on, and retrofitting placement after launch is expensive. This is where the architecture cuts both ways. A replicated edge database spreads copies of your data across jurisdictions by design, which is excellent for read latency and awkward for sovereignty. A single primary keeps the data in one place you can point to on a map, which is easier to attest to and slower for distant readers. Telnyx runs edge compute sites across North America, Europe, APAC, and MENA, and processes in-region traffic with in-region compute as a property of how the network is built rather than a configuration flag, so the data boundary follows the traffic. Whichever provider you choose, confirm the placement guarantees in writing before you migrate production data.
Two adjacent choices are worth naming. Vector search for retrieval workloads belongs in a purpose-built embeddings database rather than a relational one, even when the relational data sits nearby. And if you are still choosing a compute layer, decide that first, because the compute decision constrains the database decision far more than the reverse.
Related articles