How to Choose a Database: One Food Delivery App, From Launch to Scale

Five database families, Postgres, MongoDB, Redis, Cassandra and Neo4j, with Postgres marked as the default choice

Learning how to choose a database comes down to two honest questions: what shape is your data, and how will you actually read and write it? Logos, trends and benchmarks come last, if they count at all. When you answer those two questions first, the right choice for most backends turns out to be fairly obvious.

To make this concrete, we'll follow one example from start to finish: a food delivery startup. We'll see which database it needs on launch day, what changes when the lunch rush hits, and when specialist tools like Cassandra or Neo4j might finally make sense. Along the way you'll meet the five big database families and learn what each one is genuinely good at.

In short
  • Look at the shape of your data before you look at database names.
  • Connected data that must stay correct belongs in a relational database like Postgres.
  • Redis is a speed layer for caching and sessions, not your source of truth.
  • Cassandra and Neo4j are specialists for write floods and deep relationships.
  • Start with Postgres, and add tools only when a specific, measurable problem appears.
  1. 0:00Intro
  2. 0:28Your database choice follows you forever
  3. 1:30What shape is your data, honestly?
  4. 2:29Postgres: spreadsheets with rules
  5. 3:28MongoDB: flexible JSON folders
  6. 4:31Redis: a lightning-fast coat check
  7. 5:31Cassandra: built for massive writes
  8. 6:35Neo4j: when relationships are the point
  9. 7:38The everyday three, compared
  10. 8:30How you read and write beats hype
  11. 9:34A food delivery app, step by step
  12. 10:37How teams pick wrong
  13. 11:35Picking a database, live
  14. 12:23Boring wins
  15. 13:09What to remember
  16. 13:43Start with Postgres. Boring wins.

Why your database choice is so hard to undo

Before our food delivery app writes a single line of code, it helps to understand the stakes. A database isn't like a font you can swap whenever you like. Once your data lives somewhere, every query, every feature and every late-night bug fix depends on that decision.

The tricky part is that a poor choice rarely breaks on launch day. Picture a shop built on MongoDB because the tutorials looked slick. Everything works, until someone asks for a report that combines orders, customers, products and refunds. Suddenly the easy database feels stubborn, and every new feature gets a little harder.

Teams in that position often start stitching data together in their own code: fetch this, loop over that, match the IDs by hand. It's slow, fragile, and every new developer has to learn that homemade join logic. Moving a live app with real users to a different database later is expensive, risky and slow.

  • Bad picks fail slowly, not all at once.
  • Hand-written joins in app code invite bugs.
  • Migrating a live app is costly and risky.

What shape is your data? Sketching the delivery app

So where does our food delivery team begin? Not with the coolest-sounding option. They grab a notepad and sketch the data as it really is today, not as they hope it might look someday. That sketch reveals more than any benchmark can.

Customers place orders. Orders come from restaurants. Orders contain menu items. Payments attach to orders. Almost everything points at something else, which means this is connected data. The records are also fairly uniform: every customer has a name and contact details, and every order has a customer, a restaurant and a total.

The order of questions matters. First the shape of your data, then how you'll read and write it, and only then the database. Most people run this backwards and start with the logo.

  • Connected or separate? Do things constantly reference each other?
  • Uniform or messy? Do records share the same fields?

Launch day: why Postgres fits connected data

With a sketch full of links between customers, restaurants, orders and payments, the delivery app has a textbook case for a relational database like Postgres. Think of it as spreadsheets with a strict teacher standing behind them. Data lives in tables with fixed columns, tables link through IDs, and the database itself enforces the rules instead of hopeful app code.

The feature relational databases are known for is the join. One query can pull orders together with the matching customer names in a single step. There's no looping in the app and no manual stitching. Decades of engineering have gone into making those joins fast and correct.

Payments add a second reason. Transactions mean a change happens completely or not at all. If money moves from one account to another, both sides update, or neither does. For a delivery app taking real money, that guarantee isn't optional.

# orders with their customer names
SELECT o.id, c.name, o.total
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.total > 50;

Should the menus live in MongoDB instead?

Someone on the team might point out that menu items vary. A pizza has sizes and toppings, while a drink might only have a volume. Isn't that a job for MongoDB? Document stores are like a filing cabinet of folders, where each folder holds one JSON document and no two folders need to look the same.

That flexibility is real, and it's why people like Mongo for product catalogs, blog content, form submissions and logs. If forcing every item into the same columns would leave a table full of empty cells, documents can feel natural.

The catch appears when documents need to reference each other heavily. You either duplicate data or rebuild joins in your app, and both get messy. Our menu items are tied to restaurants and orders, so they stay in Postgres, which can also store JSON in columns for the parts that genuinely vary.

{ "name": "Trail Runner",
  "type": "shoe",
  "sizes": [40, 41, 42],
  "colors": ["red", "black"] }

Lunch rush: adding Redis as a cache

The app grows. At lunchtime, thousands of people load the same popular menus at once. This is a real, measurable pain, and that is exactly when the team adds a new tool: Redis, a key-value store.

Redis works like a coat check. You hand over a coat, get a ticket, and that ticket returns your coat instantly. A key, such as a session for user forty-two, points to a value. Because Redis keeps data mostly in memory, lookups are extremely quick compared with reading from disk.

Now a request checks Redis first. If the menu is cached, it comes straight back. If not, the app reads from Postgres and saves a copy in Redis for next time. Postgres stays the source of truth while Redis absorbs the stampede, along with login sessions and rate-limit counters. Memory is fast but forgetful, so the permanent copy always lives elsewhere.

Driver pings and recommendations: Cassandra and Neo4j

Much later, two new needs might appear. Drivers could send location pings nonstop, or the team might want smarter recommendations. Each points to a different specialist.

Wide-column stores like Cassandra exist for a firehose of writes, more than one machine can handle. Data is spread across many ordinary machines, with copies kept on others, so losing one doesn't stop the cluster. The price is flexibility: you design tables around your queries up front, and ad-hoc questions and joins are off the menu.

Graph databases like Neo4j suit questions where the connections matter most. People, places and products become nodes, and links like 'bought' or 'likes' are stored directly. Questions that hop several links deep, such as friends of friends who like the same things, are natural for a graph. For listing and filtering ordinary records, though, a graph only adds complexity.

  • Cassandra: telemetry, message history, tracking events.
  • Neo4j: recommendations, fraud rings, people you may know.

Postgres vs MongoDB vs Redis: let access patterns decide

Postgres, MongoDB and Redis are the three most beginner backends end up choosing between. Postgres thinks in tables and is best at connected, consistent data. MongoDB thinks in documents and suits varied records. Redis thinks in keys and values and excels at caching. They aren't rivals, either; many real apps pair Postgres for truth with Redis for speed.

What settles the choice is how your app reads and writes, not trendy posts or benchmarks that test someone else's workload. Our delivery app joins related data constantly, writes a steady trickle of orders, and needs payments to be exactly right. Each answer points to the same place.

Walk your own app through the same questions in order, and the field narrows quickly.

  • How do you read? By ID suggests key-value; filters and joins suggest relational; following links suggests a graph.
  • How do you write? A steady trickle suits relational; a nonstop firehose suits Cassandra-style tools.
  • How wrong can a read be? Briefly stale may be fine for a like counter; payments must be exact.

Common mistakes when choosing a database

Our delivery team avoided the traps that catch many others, and each one has a simple fix. The first is choosing by vibes: MongoDB sounded modern, so in it went. Instead, sketch your data, list your reads and writes, and let the workload pick.

The second is treating the coat check like a vault, keeping your only copy of orders or accounts in a cache. The third is building for scale you don't have, like running Cassandra for a few hundred users. The fourth is rebuilding joins in app code, which is a strong sign your data is relational and wants a database that joins.

  • Choosing by hype → start from shape and access patterns.
  • Redis as main store → cache copies, keep truth elsewhere.
  • Planning for fake scale → design for your next stage.
  • Faking joins in code → use a database that joins.

Why 'start with Postgres' is the safe default

The delivery app's story leads to one rule: start with Postgres unless you have a clear reason not to. It isn't exciting advice, which is exactly why it works. Postgres has been around for decades, it's open source, and a huge community knows it well, so answers to late-night problems are usually easy to find.

A clear reason means a specific pain, such as 'we write sensor readings nonstop' or 'our whole product is a social graph', not 'it felt modern.' Postgres also stretches further than many expect, with JSON columns, full-text search and solid indexing covering many cases people assume require Mongo.

Key takeaways

  • Ask what shape your data honestly has before comparing databases.
  • Use Postgres for connected data that must stay consistent.
  • Treat Redis as a speed layer, never the only copy of important data.
  • Reach for Cassandra for write floods and Neo4j when relationships are the point.
  • Add each new tool only when a specific, measurable problem shows up.

Frequently asked questions

Should I use MongoDB or Postgres for a new backend?

If your records reference each other a lot, like users, orders and products, Postgres is usually the better fit because it handles joins and transactions well. MongoDB suits records that genuinely vary and don't need heavy linking, such as catalogs, content or logs.

Can Redis be my main database?

It's risky to use Redis as the only home for important data, because it keeps data mostly in memory. Use it to cache copies, store sessions and count rate limits, and keep the permanent version in a database like Postgres.

When does Cassandra make sense?

Cassandra fits workloads with a constant, very large flow of writes, such as device telemetry, message history or tracking events. You give up flexible queries and joins in exchange, so it's overkill for a typical app with modest traffic.

Do I need a graph database for recommendations?

A graph database like Neo4j shines when questions hop many links deep, such as friends of friends who like the same things. If your app mostly lists, filters and updates records, a graph adds complexity without much benefit.

Can I use more than one database in the same app?

Yes. Many real apps run Postgres as the source of truth with Redis in front for speed. The key is to add each one because of a specific problem, not all at once on day one.

What would you pick for a simple habit-tracker app?

Users have habits, and habits have daily check-ins, so the data is connected. Reads involve streaks and date filters, writes are a few per user per day, and streaks must be accurate, so Postgres fits, with a cache added only if pages later get slow.

Watch the full video on YouTube →

Souy Soeng

Souy Soeng

Hi there 👋, I’m Soeng Souy (StarCode Kh)
-------------------------------------------
🌱 I’m currently creating a sample Laravel and React Vue Livewire
👯 I’m looking to collaborate on open-source PHP & JavaScript projects
💬 Ask me about Laravel, MySQL, or Flutter
⚡ Fun fact: I love turning ☕️ into code!

Post a Comment

CAN FEEDBACK
Ad