Back to blog
Sep 06, 2026
6 min read

Two ways to store data, and one way to not get robbed

A database is how an app remembers anything after you close the tab. A stop on the roadmap: the two shapes data comes in, how to pick one, and the one-line habit that keeps a stranger from reading your whole database.

This stop on my roadmap is the database, the part of an app that remembers. Everything before this vanishes the moment the tab closes: type into a form, refresh, it is gone. A database is where things are kept so they survive. What surprised me is that there are really only two shapes to keep them in, and one small mistake in how you read them back that can hand an attacker the whole thing.

Two ways to keep what you store

Imagine an office keeping records. One way is a filing cabinet: labelled drawers, every folder the same shape, a form with the same fields every time. Rigid, but you always know where everything is and nothing goes missing. The other way is a wall of labelled boxes: each box can hold whatever shape of thing you throw in. Flexible, but there is no guarantee two boxes hold the same kind of thing.

Those two are the two families of database.

  • SQL databases are the filing cabinet. Data lives in tables: rows and columns, every row the same shape, like a spreadsheet. They are strict, reliable, and great when your data has clear relationships (a user has orders, an order has items). SQL is the language you use to ask them things. Examples: PostgreSQL, MySQL, SQLite.
  • NoSQL databases are the labelled boxes. Data lives as flexible documents or simple key-value pairs, and each record can look a little different. Good for fast-changing or loosely shaped data. Examples: MongoDB, Redis, Firebase.
flowchart TD
  Q{Does your data have a clear,
  stable shape and relationships?} -->|yes| SQL[SQL: tables, strict, reliable]
  Q -->|no, it is loose or
  changes a lot| NO[NoSQL: documents, flexible]
SQL (tables)NoSQL (documents)
ShapeFixed rows and columnsFlexible, per-record
Best forUsers, orders, paymentsFast-changing, loosely shaped data
ReliabilityVery strong (ACID rules)Varies by database
ExamplesPostgreSQL, MySQL, SQLiteMongoDB, Redis, Firebase

TIP

As a beginner, start with SQL. The strict table structure forces you to think clearly about your data, and those relational concepts make NoSQL easy to pick up later. Most apps a beginner builds are a natural fit for SQL anyway. ACID, by the way, is just a promise that a change either fully happens or does not happen at all, so you never end up half-saved.

The one-line mistake that leaks everything

Reading and writing is where a database gets dangerous, and it is worth slowing down for because it is the most famous beginner security hole on the web: SQL injection.

Here is the trap. You want to look up a user by what they typed, so you build the query by gluing their input straight into the text:

// whatever the user typed goes straight into the query text
db.query("SELECT * FROM users WHERE name = '" + userInput + "'")

If a user types a normal name, fine. But if they type ' OR '1'='1, the query now reads “give me every user where the name matches, OR where 1 equals 1”, and 1 always equals 1. They just asked for your entire users table, and the database happily obeyed, because it could not tell the difference between your command and their input.

The fix is one habit, used every single time: parameterized queries. You write the query with a placeholder, and pass the user’s value separately. The database then treats that value strictly as data, never as part of the command.

// the ? is a placeholder; the value is passed apart from the query
db.query("SELECT * FROM users WHERE name = ?", [userInput])

CAUTION

Never build a query by joining strings with user input, not just on login forms, everywhere. Use placeholders for every value that came from outside. This one habit closes the most common serious hole in web apps, and most database tools do it for you if you let them.

For extra safety, the pros stack two more cheap habits on top: give the app’s database account only the permissions it actually needs (so a leak cannot drop your tables), and validate input before it ever reaches the query.

Tools, and a shortcut worth knowing

All free and open-source unless noted.

JobPopular toolsNote
SQL databasePostgreSQL, MySQL, SQLiteSQLite is a single file, perfect to learn on
NoSQL databaseMongoDB, Redis, FirebaseFirebase is hosted, free tier then paid
Talking to the DB safelyPrisma, Drizzle (ORMs)Parameterize for you, so injection is hard to get wrong
Going deeper: what an ORM saves you from

An ORM (Object Relational Mapper) is a tool that lets you read and write the database using normal code objects instead of raw SQL strings. user.create({ name }) instead of writing the INSERT yourself. The reason it matters for this stop: a good ORM builds parameterized queries by default, so the injection trap above is closed for you unless you deliberately go around it. For a beginner, that is a real safety net, not just convenience.

Pick a shape, then guard the door

The lasting lesson from this stop is two decisions, not a hundred. First, pick the shape that fits your data: strict tables for anything with clear relationships, flexible documents for loose or fast-changing data, and SQL first while you are learning. Second, and this one is not optional, read and write with placeholders so a stranger’s typing can never become a command. The first choice affects how comfortable your app is to build. The second decides whether it can be robbed.

Choose the shape for you, and the placeholders for everyone else.

Sources

Read next