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) | |
|---|---|---|
| Shape | Fixed rows and columns | Flexible, per-record |
| Best for | Users, orders, payments | Fast-changing, loosely shaped data |
| Reliability | Very strong (ACID rules) | Varies by database |
| Examples | PostgreSQL, MySQL, SQLite | MongoDB, 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.
| Job | Popular tools | Note |
|---|---|---|
| SQL database | PostgreSQL, MySQL, SQLite | SQLite is a single file, perfect to learn on |
| NoSQL database | MongoDB, Redis, Firebase | Firebase is hosted, free tier then paid |
| Talking to the DB safely | Prisma, 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
- Splunk: SQL vs NoSQL, differences and when to use which for the table vs document split and use cases
- Coursera: SQL vs NoSQL, when to use each for the beginner “start with SQL” guidance and ACID
- OWASP: SQL Injection Prevention Cheat Sheet for parameterized queries and least privilege
- SecureLayer7: parameterized queries and how they stop SQL injection for the injection example and the safe pattern