Back to blog
From ScyllaDB to SQLite
infrastructureself-hostingtechnicaldatabase

From ScyllaDB to SQLite

Why I dropped a distributed NoSQL database in favor of a single file, and what that means for self-hosting Gryt on any platform.

Sivert·

Title: From ScyllaDB to SQLite: picking a database for self-hosted chat
Date: 28 February 2026
Author: Sivert Gullberg Hansen
Keywords: SQLite, ScyllaDB, PostgreSQL, self-hosting, Windows, WAL

Abstract

Gryt's server started out on ScyllaDB, a distributed NoSQL database built for high write throughput. That made sense on paper, but ScyllaDB doesn't run on Windows, and a lot of the people who want to host a server for their friends are on Windows. This post weighs ScyllaDB against SQLite and PostgreSQL for the servers Gryt actually runs: dozens to hundreds of people, hosted by someone who isn't a sysadmin. SQLite won. It needs no install, no service and no configuration, runs on every platform, and the whole database is one file you can copy. The cost is a single writer at a time, no replication and no horizontal scaling, none of which matter at Gryt's size. PostgreSQL is the next step if SQLite ever stops coping.

1 Introduction

Gryt is self-hosted software. The whole point is that you run it on your own hardware, on your own terms. I kept hearing variations of the same question: "Can I just run this on my Windows PC?" And honestly, the answer was always some version of "kind of, but you need Docker, and you need to configure this, and you need to make sure WSL is set up correctly, and..."

That's not good enough. If someone downloads the Gryt server and wants to host a server for their friends, they shouldn't need to become a sysadmin first. So this post asks:

  1. What does a database for a self-hosted Gryt server need to do?
  2. Which database meets that best, and what does the choice cost?

2 Background

When I first designed Gryt's server stack, I picked ScyllaDB [1], a high-performance NoSQL database compatible with Apache Cassandra's query language. ScyllaDB is fast, horizontally scalable, and built for workloads with high write throughput. Chat messages, presence updates and audit logs are all write-heavy patterns that ScyllaDB handles well.

If you read Inside Gryt's Infrastructure, you'll see ScyllaDB right there in the architecture diagram. Each server instance got its own keyspace, data was isolated, and the whole setup felt properly engineered.

ScyllaDB doesn't run on Windows. Not natively, not in WSL (reliably), and not without Docker, which brings its own set of problems. Docker Desktop on Windows is a second-class experience for a lot of users. Network bridging behaves differently, filesystem mounts are slow, and asking someone to install Docker just to run a database that's overkill for a 20-person friend group felt wrong.

3 Method

I compared the three databases against what a self-hosted Gryt server needs. The workload is dozens to hundreds of concurrent users rather than millions, mostly writes: messages, presence and logs. The person running it may be on Windows and may never have run a database before. From that come five requirements:

  • runs natively on Windows, Linux and macOS, on ARM and x86
  • needs no separate service, port or credentials
  • can be backed up and moved without tools
  • handles concurrent reads and writes at Gryt's size
  • has a way up if a server outgrows it

4 Results

Table 1 has the comparison.

Table 1: The three databases against a self-hosted Gryt server's requirements.

ScyllaDBSQLitePostgreSQL
Runs natively on WindowsNoYesYes, as a separate install
Separate service to runYes, a containerNo, it's inside the server processYes
ConfigurationConnection, cluster, keyspaceNoneConnection string, credentials
BackupIts own toolingCopy one filepg_dump or replication
Concurrent writesYesOne writer at a timeYes
Replication and scaling outBuilt inNoneRead replicas

SQLite [2] is the only one that meets the first three requirements. It's the most deployed database in the world, and the entire database is a single file:

  • Zero configuration. Start the server, it creates a gryt.db file, done. No connection strings, no cluster setup, no keyspace provisioning.
  • Runs on Windows natively. No Docker required. No WSL. Just run the binary.
  • Easy to back up. Copy one file. That's your backup. Want to migrate to a new machine? Move the file.
  • No extra services. The old stack needed a ScyllaDB container running alongside the Gryt server. Now the database lives inside the server process itself.

For the fourth requirement, the server uses better-sqlite3 [3], a synchronous C binding with no async overhead and no connection pool management. Queries run on the calling thread and return immediately. The server turns on WAL mode [4] at startup, along with a 5-second busy timeout. With WAL, readers don't block writers and writers don't block readers, so even if several operations hit the database at once, they queue up and resolve without errors. The schema has indexes on the columns that matter: message timestamps, user IDs, conversation lookups and job queues. Prepared statements are reused across requests. For a server hosting a few hundred people, query times are measured in microseconds, not milliseconds.

People hear "SQLite" and assume "slow" or "toy database." It's neither. ScyllaDB is designed to handle millions of operations per second across distributed clusters. Gryt, at its current scale, doesn't need that. Not even close. Using ScyllaDB for a 30-person friend group is like hiring a freight train to deliver a pizza.

4.1 What changed in the stack

The schema stayed conceptually the same, with the same tables, the same relationships and the same data. What changed was the implementation:

  • ScyllaDB (CQL) was replaced by SQLite via better-sqlite3
  • Docker Compose no longer needs a ScyllaDB container
  • The server binary is fully self-contained, with no external database dependency
  • Data lives in a single gryt.db file in the configured data directory
  • Foreign key constraints are now enforced (something CQL didn't support natively)

For existing self-hosters running the old ScyllaDB setup, the migration path is documented in the deployment guide [5]. For new users, you don't need to think about any of this.

5 Discussion

5.1 Limitations

I won't pretend this is a perfect decision with no downsides:

  • SQLite doesn't scale horizontally. If a single Gryt server ever needed to handle tens of thousands of concurrent users with millions of messages, SQLite would become a bottleneck. Write contention would increase, and there's no way to shard across machines.
  • No built-in replication. With ScyllaDB, you got automatic replication across nodes. With SQLite, if the disk dies, you need a backup. There's no replica sitting on another machine ready to take over.
  • One writer at a time. WAL mode allows concurrent reads, but writes are still serialized. For Gryt's current traffic this is fine, since writes are fast enough that the serialization is invisible. But it's a ceiling that exists.

These matter at a scale Gryt hasn't reached, and may not reach for a long time.

5.2 Future work

If Gryt grows to the point where SQLite becomes a bottleneck, the most likely next step is PostgreSQL [6] rather than a return to ScyllaDB. Postgres gives you read replicas, true concurrent writes, a huge ecosystem of tools and managed hosting, and SQL, so moving from SQLite would be relatively straightforward.

I haven't built a database abstraction layer yet, and I'm not building one ahead of time. Right now, the code talks directly to better-sqlite3. If Postgres support becomes necessary, I'll add it as a second backend. If people are hosting servers with thousands of users and SQLite is genuinely struggling, that's a great problem to have, and one I'll address when it arrives.

6 Conclusion

What does a database for a self-hosted Gryt server need? To run on any platform someone might host from, Windows included, with nothing to install or configure, and to be easy to back up. Raw throughput matters far less at dozens to hundreds of users.

Which one meets that best? SQLite. It runs inside the server, everywhere, as one file. It costs scaling out and replication, which Gryt doesn't need yet, and PostgreSQL is the way up if it ever does.

Removing ScyllaDB also meant fewer containers, fewer ports, fewer environment variables and fewer things to debug when something goes wrong. Questions about the migration, or want to host your own server? Come chat on our Gryt server or Discord.

References

  1. ScyllaDB. https://www.scylladb.com
  2. SQLite. https://sqlite.org
  3. better-sqlite3. https://github.com/WiseLibs/better-sqlite3
  4. SQLite. Write-Ahead Logging. https://sqlite.org/wal.html
  5. Gryt docs. Hosting with Docker Compose.
  6. PostgreSQL. https://www.postgresql.org