Computes, autoscaling, scale-to-zero and high availability
kept in this browser
Edit this pageThe Postgres computes behind a Lakebase branch, how they autoscale in capacity units, when they suspend to zero and what that costs a session, and how secondaries and read replicas differ.
On this page9
What it is
A compute is the running Postgres process that serves a branch. In the API it is called an endpoint, and there are two kinds:
ENDPOINT_TYPE_READ_WRITE— the primary. Every branch has exactly one.ENDPOINT_TYPE_READ_ONLY— a read replica, added when reads need their own capacity.
Computes are sized in capacity units (CU). One CU is about 2 GB of memory with proportional CPU and local SSD. A compute can autoscale within a range, suspend itself when nobody is connected, and, for the primary, run with standby copies in other availability zones.
Why it exists
A fixed-size database is sized for its peak and paid for at its peak around the clock. For most application databases the peak is a few hours of a working day, and for development branches the peak is “someone ran the tests”. The first version of Lakebase worked that way: instances of fixed size, resized by hand.
Separating compute from storage lets the compute follow the load instead. The data does not live on the compute, so it can grow, shrink or disappear without moving anything, and come back in well under a second.
How it works
Sizes and autoscaling
A compute autoscales between a minimum and a maximum anywhere from 0.5 to 64 CU; larger computes, up to 112 CU, run at a fixed size. The range has one rule: the maximum may be at most 16 CU above the minimum — 4 to 20 is valid, 1 to 32 is not.
Scaling follows CPU, memory and the size of the working set, the data the database keeps touching. Moving inside the configured range happens without a restart. Changing the range itself, the minimum or the maximum, can interrupt connections for a moment.
The size also bounds how many connections Postgres accepts:
| Compute size | Maximum connections |
|---|---|
| 0.5 CU | 105 |
| 8 CU | 1,795 |
| 16 CU | 3,597 |
| 32 CU and above | 3,993 |
An application with many short-lived clients runs out of connections long before it runs out of CPU. That is what the connection pooler is for (see Connecting to Lakebase, roles and permissions).
Scale-to-zero
With scale-to-zero on, a compute suspends after a period without activity: 24 hours by default, configurable from 60 seconds to 7 days, or switched off. The next connection wakes it in a few hundred milliseconds, at its minimum size, and it scales up from there.
What does not survive a suspension is the session: temporary tables, prepared statements and in-memory statistics are gone, and the connection itself has to be reopened. An application that holds a connection pool must reconnect and retry, which any production Postgres client should do anyway.
Two exceptions to keep in mind:
- A compute with high availability does not scale to zero.
- Instances upgraded from Provisioned did not get scale-to-zero turned on by default; it is a setting to change deliberately.
A short timeout on development and preview branches is where most of the saving is; a production database with steady traffic rarely suspends at all.
High availability
High availability adds one to three secondaries to the primary compute, in different availability zones. If the primary fails, a secondary takes over automatically, without losing committed transactions. Secondaries never scale below the primary’s current size, so a failover does not land on a smaller machine.
Secondaries can also serve reads. The compute has a second host name ending in -ro; connections to it are routed to the readable secondaries.
Read replicas
A read replica is a separate read-only compute on the same branch. It reads the same storage as the primary, so it adds no storage cost. Replication is asynchronous, which means a replica is eventually consistent: a row just written on the primary may not be visible on a replica for a short while. Replicas autoscale and scale to zero on their own settings, and a branch can have up to six.
| Readable secondaries | Read replicas | |
|---|---|---|
| Purpose | Survive a failure; reads are a bonus | Give reads their own capacity |
| Scale to zero | No | Yes |
| Sizing | Follows the primary | Independent |
| Consistency | Standby of the primary | Asynchronous, eventually consistent |
| How many | 1–3 | Up to 6 per branch |
Example
Adding a read replica to production for a reporting screen, so its heavy reads stop competing with checkout:
databricks postgres create-endpoint projects/shop/branches/production reporting \
--json '{"spec": {"type": "ENDPOINT_TYPE_READ_ONLY"}}'
The reporting screen connects to the replica’s host; the application keeps using the primary. A report that shows an order a second late is fine; a checkout that reads its own write from a replica is not, which is why writes and read-your-own-write queries stay on the primary.
Common mistakes
- A range wider than 16 CU. The API refuses it. Pick the band where the load actually lives.
- Sizing for connections as if they were free. Each compute size has a connection ceiling; hundreds of idle clients belong behind the pooler.
- Relying on session state. Temporary tables and prepared statements vanish when a compute suspends. Recreate them per connection, or turn scale-to-zero off where that matters.
- Reading your own writes from a replica. Replicas lag. Route those reads to the primary.
- Expecting HA to save money at night. Highly available computes do not scale to zero.