One of the questions we get most about Payload is which database it works with. The short answer: the most common ones, chosen through an adapter. But the choice matters more than it seems, because it changes how you deploy, how you migrate and how much you pay.
The adapters
Payload does not ship its own database. You install the adapter for the one you want and set it in db inside the config:
Database | Package | Notes |
|---|---|---|
MongoDB |
| Uses Mongoose. Documents, no rigid schema. |
Postgres |
| Uses Drizzle. Relational, SQL migrations. |
Postgres on Vercel |
| Variant for Vercel's Postgres. |
SQLite |
| Uses Drizzle. A local file or a libSQL server such as Turso. |
Cloudflare D1 |
| Cloudflare's SQLite, for running Payload on Workers. |
The list changes between versions, so before deciding confirm the current adapters in the Payload documentation.
How each one feels
MongoDB. Natural if your team already uses it and your data is nested. You don't need migrations to change a field. In return, relationships between collections are weaker and querying highly related data costs more.
Postgres. The sturdiest option for related data and heavy concurrency. It has tables, foreign keys and the whole SQL tooling ecosystem. What changes: you handle migrations and need a database server (your own or managed).
SQLite. A database in a file. In development it is the most comfortable: nothing to install, delete and recreate at will. In production the file only needs to be reachable, and that is where Turso comes in.
D1. Cloudflare's SQLite. It makes sense if you already deploy Payload on Cloudflare Workers, because the database connects as a binding. Outside that case there is no reason to pick it.
Migrations and development mode
With relational databases (Postgres and SQLite), in development Payload adjusts the tables on its own when you change your schema, and in production you use versioned migrations: payload migrate:create generates the SQL and payload migrate applies it. With MongoDB there are no tables to migrate. How we set it up with Turso, command by command, is in Payload CMS with Turso step by step.
How to choose
- Content site, blog, corporate site: SQLite/Turso or Postgres. Little writing, a lot of reading; either holds up.
- Application with many simultaneous writes (orders, bookings, sessions): Postgres. SQLite allows a single writer at a time.
- Your team already lives in MongoDB: MongoDB, no need to overthink it.
- Everything on Cloudflare: D1.
- You want local and production to be as alike as possible without installing anything: SQLite, with a file locally.
What we chose and why
For this site we use SQLite locally and Turso in production: content that is read a lot, few writes, and the same adapter in both environments. It is not a universal decision. If the project were a store with concurrent orders, we would go with Postgres. The full CMS comparison is in Payload vs Strapi vs Directus, and the rest of the stack in how codegea.com is built.
Written by
Derian Pinto
Founder & Full Stack Developer
Founder of Codegea. Builds custom websites, stores and platforms, and integrates and supports Arc XP for media companies.