# Xata: self-hosted Postgres with copy-on-write branching

> Xata is an Apache 2.0 licensed platform that runs many Postgres instances on Kubernetes with storage level copy-on-write branching, scale-to-zero hibernation, a REST control plane and a CLI, and the README says plainly where it is the wrong choice.

**xataio/xata** — Open source, cloud native, Postgres platform with copy-on-write branching and scale-to-zero

- Repository: https://github.com/xataio/xata
- Website: https://xata.io
- Stars: 1,095 · Forks: 63
- Language: Go
- License: Apache-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/xataio-xata

## What Xata is: Postgres instances managed on Kubernetes

Xata is described as a pure open-source, cloud-native platform for self-hosting a large number of Postgres instances on top of Kubernetes. The unit of the platform is not a cluster but a set of clusters grouped into projects and branches, with a control plane over them.

The README lists the built-in functionality, and it is a good summary of the scope: fast branching using copy-on-write at the storage level, scale-to-zero that removes a compute instance on inactivity and adds it back on connection, auto-scaling of compute nodes with bin packing for cost, high availability with read replicas and automatic failover, upgrades and configuration edits with minimal downtime via switchover, separation of storage and compute, point-in-time recovery backups to object storage, a serverless driver that speaks SQL over HTTP and websockets, and REST APIs and a CLI for control plane operations authenticated with API keys that support granular RBAC.

The base layer is CloudNativePG, the Postgres operator for Kubernetes, which handles the ordinary production concerns: high availability, failover and switchover, upgrades, connection pooling and backups. Xata sits on top of that and adds a SQL gateway responsible for routing, IP filtering and waking up scaled-to-zero clusters, a branch operator that manages everything related to a branch, the clusters and projects services that form the control plane, an auth service based on Keycloak, a CLI on top of the REST API, and a scale-to-zero plugin for CloudNativePG that hibernates branches on inactivity.

The project is Apache 2.0 licensed, written in Go, and the last push to the repository was on 2026-10-15.

## Branching with copy-on-write at the storage layer

Branching is the feature the project is built around. The README describes fast branching using copy-on-write at the storage level, and the claim is that you can copy terabytes of data in a matter of seconds.

The mechanism is what makes that possible. Copy-on-write at the storage level means a branch does not copy the data blocks; the new branch shares the underlying storage with its parent, and blocks are duplicated only when they are written to. A branch created from a production database therefore costs almost nothing to create, which is what makes the second use case in the README practical: preview, testing and development environments that hold terabytes of data each.

That is a materially different approach from cloning a Postgres instance with pg_basebackup or from dumping and restoring, both of which move the full data set and take time proportional to its size. With copy-on-write, the branch operation is metadata, and the cost of a branch is paid later by whoever writes to it.

The trade-off is the usual one for shared storage. A branch that writes heavily diverges from its parent and consumes real space, and the platform has to decide when to split a block out. The README does not document the block size, the divergence policy or the point at which a branch stops being cheap, so a team planning a branching strategy should measure that themselves rather than assume the seconds figure holds for write-heavy branches.

## Scale-to-zero, the SQL gateway and the serverless driver

Scale-to-zero is the second pillar, and it is the feature that makes many small Postgres instances affordable. The platform can remove the compute instance when a branch is idle and bring it back automatically on connection. A CloudNativePG plugin handles the hibernation, and the SQL gateway is the component that wakes a scaled-to-zero cluster when a query arrives.

The serverless driver is what makes that invisible to a client. Instead of a long-lived TCP connection to Postgres, the client speaks SQL over HTTP and websockets, and the gateway routes the request, waking the branch if it was asleep. The same gateway handles IP filtering, so access control for a branch is a gateway concern rather than something each instance enforces.

This design has consequences for how you use it. A connection to a cold branch pays the wake-up cost, so a workload with a steady trickle of short queries can be worse off than one with a steady stream. And a client that expects a normal Postgres wire protocol has to be changed to use the HTTP or websocket driver, unless it connects to a branch that is awake.

For a preview environment, the economics are clear: dozens of branches can sit at zero cost, and a reviewer opens one, it wakes, and it is closed again. That is one of the two use cases the README names, and it is the one where the scale-to-zero design pays for itself without a client rewrite.

## The control plane, the CLI and API key management

Everything an operator does goes through the control plane. The clusters and projects services hold the state, the REST APIs expose it, and the CLI is a client of those APIs rather than a separate path into the cluster. The auth service, based on Keycloak, handles identity, and API keys carry granular RBAC, so a client can be granted narrow permissions instead of cluster-wide access.

The API surface is defined in the repository as OpenAPI files and protobuf, and the Go services are built with buf, with a Makefile and a Tiltfile driving the development loop. The tree is arranged as a set of services/, internal/ packages, charts/ for Helm, kustomize/ for overlay based deployment, gen/ for generated code, and cue/ for configuration, with the Dockerfile and docker-bake files driving image builds.

Using the CLI against a local development environment is a short sequence of commands after authentication, and the local setup is deliberately close to production. The first project and branch are created like this:

```bash
# Create project and main branch
$ xata project create --name my-project

# Create a child branch
$ xata branch create
```

The child branch inherits the parent's data through the copy-on-write storage, which is the whole point of the branching model: a development environment is a branch of production, not a restored copy of it.

## Running the platform locally with Kind and Tilt

The README gives a local quick start that assumes Docker, Kind for a local Kubernetes cluster and Tilt for the deployment loop. The cluster comes first, and the wait flag gives the control plane time to come up:

```bash
kind create cluster --wait 10m
```

Then the platform itself is deployed with Tilt, which reads the Tiltfile at the repository root:

```bash
tilt up
```

The README warns that the first run can take a long time because all the required images have to be downloaded, and that later runs are much quicker. That is the normal experience with a Kubernetes stack of this size and it is worth budgeting for before the first attempt.

The CLI is installed separately and then pointed at the local profile:

```bash
# Install CLI
curl -fsSL https://xata.io/install.sh | bash

# Authenticate to a local profile. Sign in with email dev@xata.tech and password Xata1234!
xata auth login --profile local --issuer http://localhost:8080/realms/xata --api-url http://localhost:5001 --client-secret devsecret

# Set the profile
xata auth switch local
```

The login command names the Keycloak realm URL and the local API URL, and the profile is switched afterwards so the other commands use it. The credentials in the README are the development ones baked into the local Keycloak, which is fine for a laptop and obviously not for anything else.

The Go module declares a recent toolchain:

```go
module xata

go 1.27.1
```

## Where the README says not to use Xata, and what to compare it against

The README has a section titled when not to use Xata open source, and it is unusually direct.

The first case is a single Postgres instance. Xata runs on Kubernetes, and for one database that is overhead without benefit, so a plain self-hosted Postgres or a managed service is the better answer. The second case is a public Postgres-as-a-Service offered to end customers. The README says the licence permits it and that the authors have no intention of changing that, but they do not recommend it, because some security features related to adversarial multi-tenancy have been kept closed source. For that scenario the README points at the Xata BYOC offering.

The alternative to the first case is CloudNativePG on its own, which the README names as the underlying technology and describes as less opinionated and less feature rich than Xata. The difference in approach is real: an operator gives you Postgres lifecycle management and leaves everything else to you, while Xata adds branching, scale-to-zero, the SQL gateway, the auth service, the control plane APIs and the CLI on top. If you only need high availability and upgrades, the operator is less to run. If you need branches and hibernation, they are the reason to adopt Xata.

The hosted alternative is Xata Cloud, which the README recommends if you would rather have a managed service, and states that the open-source platform already powers it in production at scale.

## Licence, upgrades and the operational cost

The licence is Apache 2, which is permissive and includes an explicit patent grant, and the README states the project is stable and actively developed, with the last push to the repository on 2026-10-15. The repository publishes no GitHub releases, so the version to pin is in the container images and the charts rather than in a tag list, and that is a detail to settle before a first production deployment.

The operational cost is dominated by Kubernetes itself. A cluster has to run, and on top of it the control plane services, the SQL gateway, the Keycloak realm and the CNPG resources for every branch. The auto-scaling and bin-packing of compute nodes reduce the cost of many instances, but they do not remove the need to watch the platform. Upgrades are handled through CloudNativePG with switchover, which the README describes as minimal downtime, so the operator still has to plan them and watch them.

Backups are PITR to object storage, which means the object store and its credentials become part of the recovery story. A team taking this on should read the branch and backup sections of the linked architecture post first, because the README itself points there for the design rationale, and the branch storage behaviour is the part the documentation covers least.

## Conclusion

Xata fits a platform team that needs many Postgres instances with cheap preview branches, or a group that wants an internal Postgres-as-a-Service without writing a Kubernetes operator. It does not fit a single database or a public multi-tenant service, since the README keeps some adversarial multi-tenancy security features closed source. Check first that you have a Kubernetes cluster and can accept that upgrades and failover are handled by CloudNativePG underneath.

## FAQ

### What is Xata and what problem does it solve?

Xata is an open-source platform for running many Postgres instances on Kubernetes, with copy-on-write branching at the storage level, scale-to-zero hibernation, auto-scaling, PITR backups and a REST control plane. It is built on the CloudNativePG operator.

### How do I run Xata locally for development?

You need Docker, Kind and Tilt. Create a cluster with kind create cluster --wait 10m, deploy the platform with tilt up, then install the CLI and authenticate with xata auth login against the local Keycloak realm and API URL.

### How do I create a branch with the xata CLI?

Create a project with xata project create --name my-project, then run xata branch create to add a child branch. The child shares storage with its parent through copy-on-write, so a branch of a large database is created quickly.

### When should I not use Xata?

The README says not to use it for a single Postgres instance, since it runs on Kubernetes, and not to use it for a public Postgres-as-a-Service, because some adversarial multi-tenancy security features are closed source. A plain Postgres or a managed service is the alternative in the first case.

## Sources

- [Issues](https://github.com/xataio/xata/issues)
- [License: Apache-2.0](https://github.com/xataio/xata/blob/main/LICENSE)
- [Project website](https://xata.io)
- [README](https://github.com/xataio/xata/blob/main/README.md)
- [xataio/xata on GitHub](https://github.com/xataio/xata)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/xataio-xata
