Scalix WorldScalix World/ blog
← All posts

PostgreSQL 16, 17, and 18 on a Serverless Engine

1 August 2026 · Kiran Ravi & Akhil · 6 min read
Share on XShare on LinkedIn
Contents
  1. Picking a version
  2. The version is part of the data’s identity
  3. What stays boring
  4. Branches, restores, and why the major is fixed
  5. What we have not solved
  6. Try it
  7. FAQ

On most managed Postgres, choosing a major version is a dropdown you touch once. You pick something recent, you forget about it, and eighteen months later a maintenance window quietly moves you along.

On a serverless engine that choice behaves differently, and it took us a while to say clearly why. When a database can branch, restore to a timestamp, and suspend to nothing between connections, the major version stops being a property of a running server. It becomes a property of the data.

ScalixNova now offers PostgreSQL 16, 17, and 18. Here is what that means once compute and storage are separated, and what we have not solved.

Picking a version

You choose the major at creation, and only at creation:

curl -X POST https://api.scalix.world/v1/databases \
  -H "Authorization: Bearer $SCALIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "prod", "pg_version": "18" }'

Omit pg_version and you get 16, the default. Ask for something unavailable and you get a 400 whose message lists the set that is available. The failure mode we refused to ship was the silent downgrade: you request 18, the platform hands you whatever binaries the host happens to have, and you find out during a migration that needs a feature your server does not have.

The supported set comes from one shared definition read at two edges: the gateway validates your request before a database exists, and the compute plane uses the same list to select server binaries. There is no gap where the API accepts a version the compute layer cannot start. For operators running Scalix on their own hardware that list is configuration rather than a rebuild, so a host without a given major fails closed instead of guessing.

The version is part of the data’s identity

A ScalixNova database has no long lived server process to attach a version to. Compute is acquired when you connect and released when you are done. What persists is the data directory, the base backups, and the archived write ahead log. We walk through what each of those layers actually guarantees in how durability works in ScalixNova. So the question “what version is this database” cannot be answered by asking a running process. It has to be answered by the storage.

Postgres already solved this and we use its answer. initdb stamps the major into PG_VERSION in the data directory, and every path that starts a server against existing data reads that file to choose binaries. Cold start, branch, restore from a base backup, replay to an LSN: all of them resolve the major from the data, not from the request that triggered them.

The practical rule that falls out is: the backup’s major wins. If a base backup came off a 17 server, it is replayed by 17 binaries, even if the environment around it has a different opinion. That is the only version of this that is safe, because Postgres itself will refuse to start otherwise, and the alternative is a restore that fails at the worst possible moment.

The same logic runs one layer up. pg_basebackup is version matched per worker to the server it backs up, because a 16 client cannot take a base backup of a 17 or 18 server. On a single version fleet you never notice this. With three majors live at once it is a correctness requirement, and getting it wrong is quiet: it produces a database with no base backup, and therefore no restore point.

One smaller detail in the same spirit: initdb --data-checksums is explicit on every major we run. Postgres 18 turns data checksums on by default and 16 and 17 do not, so leaving it implicit would give you a fleet where checksum behaviour depends on the year a database was created.

What stays boring

None of this should reach your application, and it does not.

ScalixNova is a purpose-built storage engine that speaks the PostgreSQL wire protocol. It is not a managed wrapper around upstream Postgres, and it is not a fork. We wrote the engine deliberately, for reasons we go into in built, not assembled. From your side of the socket the contract is the one you already know:

postgresql://t_a1b2c3d4e5f6:YOUR_API_KEY@db.scalix.world:6432/db_a1b2c3d4e5f6?sslmode=require

A standard DSN. psql connects. node-postgres, psycopg, SQLAlchemy, Prisma, Drizzle, and your migration tool connect. TLS is required, not optional, and connections without it are rejected. Your database role is a per database NOSUPERUSER role, assigned automatically.

The extension set is the same on every supported major. pgvector, pg_trgm, uuid-ossp, and the contrib set are available whether you picked 16 or 18, so the version choice does not quietly become an extension choice.

Everything version related is a control plane operation. Creating databases, branching, and restores go through the API, the CLI, or the SDK. Running SQL goes through your driver, unchanged. Keeping that boundary clean is why the client half of this post is so short.

Branches, restores, and why the major is fixed

The rule is: the major is fixed for the life of the database, and everything derived from that database inherits it.

Branch databases are isolated, carry their own scoped token and a TTL so scratch environments expire instead of accumulating, and run the same major as the parent. Point in time restores are the same story: base backups plus archived WAL, on a five minute bound while the database is active, with the open segment shipped when it suspends. A restore targeting a moment after the last archived point returns a 409 rather than silently handing you older data and calling it success.

Now consider what a mutable major would do to that. You have a database created on 16 and upgraded to 18 last month, and you restore to a timestamp from six weeks ago. Which binaries replay that WAL? There is no good answer. Physical WAL is not portable across majors, so a mutable major silently truncates your restore window at the upgrade boundary, and the truncation is invisible until you need it.

Pinning the major keeps the recovery window honest. Every point inside your retention is reachable with the binaries that wrote it.

A paused database also does not bill compute, which is a consequence of acquiring compute per connection rather than a Postgres feature. It is what makes “run 18 alongside your 16 for a while” a practical suggestion instead of a theoretical one.

What we have not solved

Fixing the major has a cost, and it is ours to state.

There are no in place major upgrades. To move from 16 to 18 you create a database on 18 and migrate with pg_dump and pg_restore, or with logical replication for a smaller cutover window. A managed blue and green cutover built on branching is roadmap, and roadmap is not product.

The dedicated tier runs 16 only. Multi version is generally available on the shared tier. The dedicated microVM tier is still on 16 and fails closed on other majors rather than starting something it cannot support.

The default deliberately trails the newest. New databases get 16, not 18. New majors arrive within roughly 90 days of community GA once the extension set is validated on them, each is supported to its community end of life, and default changes are announced ahead and never touch existing databases. If you want 18, ask for 18. We will not move you there while you are not looking.

Try it

If you run Postgres for a living, the question about any serverless engine is whether the boring guarantees hold. Which binaries replay your WAL. What happens when you ask for a version that is not there. Whether a restore can quietly return the wrong thing.

You can create a database on 16, 17, or 18 and check those yourself at Scalix Nova, without a card, on a one time trial credit. If you find a case where the version guarantee does not hold, we want to hear about it. Find us on Discord or X, and you will be talking to the two people who wrote the engine.

FAQ

Which PostgreSQL versions does ScalixNova support?

PostgreSQL 16, 17, and 18. You choose the major with pg_version when you create the database, or omit it to get 16, which is the default. An unsupported major returns a 400 whose message lists the versions actually available, so a create either lands on the version you asked for or fails loudly.

Can I upgrade a database from PostgreSQL 16 to 18?

Not in place yet. The major is fixed for the life of the database. To move, create a new database on the target major and migrate with pg_dump and pg_restore or with logical replication. A managed near zero downtime cutover built on branching is on the roadmap, not in the product.

Do branches and point in time restores run the same Postgres version as the parent?

Yes, and that is enforced rather than assumed. Every data directory carries its own PG_VERSION stamp, and the branch, restore, and PITR paths pick server binaries from that stamp. A base backup taken from a 17 server is always replayed by 17 binaries, even if the surrounding configuration says something else.

Is ScalixNova a fork of PostgreSQL?

No. ScalixNova is a purpose-built storage engine that speaks the PostgreSQL wire protocol, rather than a managed wrapper around upstream Postgres. From the client side nothing changes: psql, your ORM, and your migration tool connect over TLS with a standard DSN. The durability, branching, and scale to zero behaviour underneath is ours.

Kiran RaviAkhil
Kiran Ravi & Akhil

Building Scalix World — the AI-native neocloud: database, AI, compute, storage, and auth as one platform, on sovereign European infrastructure. Say hello on X, LinkedIn, or Discord.