Skip to content
E
Egmatic
Does Your Indie Game Need a Database? Files vs Servers
does my game need a databasegame database backendwhen to use a database for your gamesqliteindie game devbackend

Does Your Indie Game Need a Database? Files vs Servers

Most indie games never need a database. You need one only for shared world state, cross-player queries, or many writers at once; files carry the rest.

Vladislav KovnerovOctober 9, 202612 min

Most indie games never need a database. A save file, a settings file and the store's cloud sync carry a single-player game all the way to release, and Minecraft's own servers carry player state for enormous communities on plain compressed files with no database in sight. A server database earns its keep under three conditions: several writers touching the same data at once, queries that cross players, and more than one server process needing the same live state. If none of those describe your game, everything else is a file wearing a database costume.

The question itself has a lineage worth respecting. In September, a developer asked r/gamedev why some games use databases, citing Tibia of all things, and the thread sat at zero replies. Our community reads for this blog flagged it as an unanswered want, squarely in the no-backend territory most readers of this site live in. It is a good question asked slightly wrong, and the correction is genuinely useful: "database" is three different tools wearing one word, and picking the right one is a design decision you can make in an afternoon.

Quick answer

If your game is single-player or same-screen multiplayer, you need files, not a database: one versioned save format, written atomically, synced by whatever store you publish on. If your game has a server because players share state, an async multiplayer world, a competitive leaderboard, or an economy that outgrows time gates, the server needs a database, and an ordinary relational one is usually enough; Tibia's operators proved that at a scale most of us will never touch. Between those poles lives SQLite, a full database engine that is just a file, which covers everything a single process will ever ask of it.

Three things people call "a database"

The thread question fails because the word covers three different tools.

A storage format on disk. Save files, level files, config blobs. These are data, but nobody calls a JSON file a database until it grows indexes and transactions, at which point it has become one.

An embedded engine. SQLite is the canonical example: per its own documentation, an in-process library implementing a self-contained, serverless, zero-configuration, transactional SQL database engine. The entire database is one cross-platform file. Its makers count it among the most deployed software modules of any description, and it is widely cited as the most deployed database engine in the world; Adobe ships it as the native file format of Photoshop Lightroom. It is a real database with real SQL, and there is still no server to run.

A client-server database. PostgreSQL, MySQL, and their relatives. These exist for one reason: many writers on many machines, coordinated through a single authority over the network. Everything they charge you in complexity, they pay back in concurrent writes, locking discipline, and crash safety across processes.

A fourth category sits on top of the third: managed backend services such as Firestore, Supabase, LootLocker or PlayFab, which wrap a database in authentication, client SDKs and a bill. When a game developer says "I guess I need a database," they usually mean this shelf, and the honest answer starts one level lower.

When files are enough

Single-player games generate exactly one stream of writes per player, and files handle that gracefully. The proof is not an argument but the biggest sandbox game ever shipped: a Minecraft Java server stores each player's state as a compressed NBT file under playerdata/<UUID>.dat, the world's settings in level.dat, and terrain in region files. No database anywhere, and this design runs servers with player counts most indie multiplayer projects would celebrate.

Files have real obligations, and they are cheap to meet. A format version in every save, so old saves survive patches. Atomic writes, write to a temp file and rename, so a crash mid-save cannot corrupt hours of progress. A readable structure you can debug, which is the whole argument for JSON or another inspectable format in data-driven design. We have covered the craft of this before: what to serialize and when lives in the save system guide, and the browser persistence piece shows how the same discipline transfers to localStorage, IndexedDB and SQLite compiled to WebAssembly when there is no server at all. When the store does the syncing for you, that is the cloud saves setup, and it is still files underneath.

When one process needs to query its own data, and raw files start to feel like string-matching, the upgrade is not a server. It is SQLite: same deployment story as a file, plus transactions, indexes and crash safety. Single-player analytics exports, replay caches, level indexes; all of that is SQLite's home turf, and it never asks for a port or a password.

The three signs you need a server database

The decision is not about gigabytes. It is about who writes, and who asks questions.

  1. Simultaneous writers on shared state. An MMO world where two players open the same chest, an async multiplayer game where sessions continue while the other player is offline. One authority must order those writes, and that authority is a server with a database behind it.
  2. Queries that cross players. A top-100 leaderboard, matchmaking pools, an economy audit, "which players own this item". Once you are ranking or joining across players, files stop being the tool; this is precisely where our leaderboards-without-a-backend guide draws its line between a score table and a competitive surface.
  3. More than one live process. The day you run a second game-server process for capacity or regions, the shared state between processes needs a home neither process owns. That home is a client-server database, or a service built on one.

Cross-device identity is a fourth, softer signal: when a save must follow a player across Steam and mobile, the store syncs stop talking to each other and something neutral above both stores has to hold state, which is the subject of the cross-platform saves piece. Note what that something is: usually a small per-player record in a managed store, not a schema with forty tables.

The Tibia question, answered directly

Tibia earns its place in the question honestly. It has been online since January 1997, built by four students from Regensburg, and by CipSoft's own twentieth-anniversary figures it had collected roughly thirty million accounts. A GDC talk on its technical infrastructure described keeping around 300,000 active players running 24/7/365. The part that should humble every architecture diagram you have ever sketched came out of their database evaluation: when Tibia's operators compared their live workload on PostgreSQL 7 against Oracle RAC and IBM DB2 in the mid-2000s, PostgreSQL came out slightly faster and dramatically cheaper.

That is the scale at which "games like Tibia" still run an ordinary relational database. The database was never the hard part. The hard part is the discipline around it, the server code that keeps a world authoritative, consistent and backed up. The private-server scene around the game makes the same point at hobby scale: OpenTibia servers keep accounts, players, houses and their items in a separate SQL database, MySQL for hosted servers, a single SQLite file for running one locally.

So the answer to "why do some games use databases" is: because their worlds are shared and concurrent to a degree files cannot referee. Tibia did not choose a database to feel enterprise. A world that two thousand characters write to at the same time is exactly the workload transactions were invented for.

What each option actually costs

OptionBest forFree floorWhat you own at 3 a.m.
Plain filesSingle-player saves, settings, unlocks$0A format and a backup routine
SQLiteOne process that queries its own dataPublic domainOne file and a backup routine
Managed backend (Firestore, Supabase, LootLocker)Auth, leaderboards, shared state without opsGenerous tiers, per-call shapedBilling alarms and quota dashboards
Self-hosted PostgreSQL on a VPSFull control, batch workloads, weird requirementsA few euros a monthEverything: updates, backups, failover

The managed tiers are more generous than their reputation, in shapes that matter. Firestore's no-cost Spark tier allows 50,000 reads, 20,000 writes and 20,000 deletes per day with 1 GiB stored and 10 GiB of monthly egress, and when the daily quota is spent it blocks further operations until reset rather than billing you. Supabase's free plan carries a 500 MB PostgreSQL database, 50,000 monthly active users of authentication and unlimited API requests. LootLocker, built for game accounts and progression, runs a 1,000-player trial tier with a free licence for non-commercial games. At the self-hosted end, Nakama is an open-source game server under Apache-2.0 that bundles the storage, and plain PostgreSQL runs on VPS sizes that cost less than a coffee.

The real line is not the price but the shape. A longtime r/gamedev regular who ran a small game's PHP backend for about a decade on €10 to €50 a month distilled the whole subject into one rule worth framing: never pay per call for what you can batch. Per-call pricing is a tax on chatty design; a client that saves after every coin collected turns a free tier into an outage at noon and a bill at midnight. Batch the writes, queue them, flush on interval and on exit, and both tiers and VPSes shrink to fit. One more shape worth knowing before it bites: Supabase pauses free projects after a week of inactivity, so a game with weekend traffic meets a cold resume on Saturday morning unless the traffic keeps it warm.

A decision pass you can run this afternoon

  1. Inventory the data. Player-local (saves, settings, unlocks) versus shared (scores, worlds, matchmaking). Draw the line on paper; most "we need a backend" feelings die on this line.
  2. Count the writers. One writer per record, ever, means files or SQLite. Two or more writers on the same record means a server and a database behind it.
  3. List the queries. If every question is "give me this player's stuff", files answer it. The first question that names two players at once, "who is ahead", "who owns this", is your migration trigger.
  4. Pick the cheapest thing that survives those answers, and write the export button before you write the first schema. Data that can leave in one file is data that can survive every mistake you are about to make, a lesson the version control and backups guide extends to the rest of the project.
  5. Instrument, then let evidence argue. Analytics is usually the first genuinely shared data an indie game produces, and the analytics for indie games guide covers what is worth collecting before you decide where it must live.

Common mistakes

Commissioning a backend for multiplayer "someday". The criteria above either fire or they do not. A single-player game with a database attached is carrying a second product's worth of failure modes for a feature it does not have.

Paying per call for batchable work. The coin-save client is the classic. Writes coalesce; a leaderboards design that batches score submissions survives its own success on any pricing model.

A "leaderboard" that lives in the client. Any score the client reports and the client stores is a suggestion, not a score. Competitive surfaces are server-authoritative or they are decoration.

A database as a save format. Player saves are blobs: written whole, read whole, versioned simply. Normalizing a save into thirty tables buys you migrations for breakfast and gains nothing, because nobody queries two players' saves against each other.

No exit. Whether files or Firestore, the day-one question is "how does everything get out". Export is the cheapest insurance in this whole article, and the only one that also survives vendor shutdowns, pricing changes and your own redesigns.

How Egmatic fits

Egmatic, the no-code 2D editor this blog belongs to, is being built around a bet that the decision pass above should not be every developer's rite of passage. Persistence belongs on the ship layer, next to publishing and analytics: sized to the game, files and store sync while the design is single-player, services when it goes shared, configured rather than commissioned. The AI inside the editor plays the same role it plays everywhere in Egmatic, a craft amplifier under your direction: you decide what your game's data means and which records are shared, it drafts the plumbing, and every file stays yours. We will state the stage plainly: Egmatic is pre-alpha, we announce no dates we cannot keep, and the waitlist at egmatic.com is where you can tell us what your game would store first, because requests that arrive during pre-alpha are the ones that steer what the layer covers.

Game data that never becomes a sysadmin job.

Egmatic is a no-code 2D editor and engine with a ship layer under construction: persistence sized to your game, files while it is single-player, services when it goes shared. Reply on the waitlist with what your game would store first: requests sent during pre-alpha are the ones that steer the build.

No spam. Unsubscribe anytime.

Conclusion

Files are not a compromise; for one writer and one process they are the correct tool, and Minecraft's file-based servers are the existence proof at any scale you are likely to meet. SQLite carries a single process into real queries without changing the deployment story. A server database is earned by concurrent shared state and cross-player questions, at which point an ordinary PostgreSQL is enough, as the people running one of the oldest MMORPGs alive demonstrated with their own benchmarks. Choose by writers and queries, keep an export under everything, and batch what would otherwise be billed per call: that is the whole discipline, and it fits on an index card.

Sources

Related Posts