You leaned back in your chair as the terminal scrolled past.
Green logs.
No warnings.
The server restarted cleanly.
Confident, you opened the database.
Empty.
Tables were there — but the rows were gone.
Clean. Fresh. Like nothing had ever lived there.
“That makes no sense,” you said out loud.
“I didn’t delete anything.”
You stood up and walked to the whiteboard, uncapping a marker.
“This,” you said, drawing a large rectangle, “is my database.”
You paused.
“It’s not just code,” you realized.
“It’s where my code leaves permanent marks.”
The Database (A Real System)
It’s easy to forget what a database really is.
When you’re working in JavaScript, everything feels temporary.
Variables come and go.
Functions finish and disappear.
But a database isn’t like that.
- Tables are real
- Rows are real
- And once they’re gone, they don’t come back just because you didn’t mean it
You wrote the line you trusted:
sequelize.sync()
“This is just setup,” you thought.
“Just making sure things exist.”
What sequelize.sync() Actually Does
You drew two columns on the board:
Left: Sequelize models
Right: Database tables
When your app starts, Sequelize compares these two worlds.
It asks simple questions:
- Does this table exist?
- Does this model exist?
If a table is missing, Sequelize creates it.
If a table already exists, it leaves it alone.
That’s sequelize.sync().
Helpful. Predictable. Mostly safe.
So why was your data gone?
You looked back at your code and noticed one small detail.
The Option That Changes Everything
You added another line beneath it:
sequelize.sync({ force: true })
One extra option.
One extra word.
It didn’t look dangerous.
It didn’t look dramatic.
But it meant something very specific.
force: true doesn’t ask questions.
It says:
“Whatever is there — remove it.”
What Happens Behind the Scenes
Sequelize doesn’t work in abstractions.
It translates your models into real SQL commands.
When force: true is present, the commands look like this:
DROP TABLE users;
DROP TABLE orders;
DROP TABLE products;
CREATE TABLE users (...);
CREATE TABLE orders (...);
CREATE TABLE products (...);
The tables come back.
Your data does not.
From Sequelize’s point of view, the job was done perfectly.
The Trap You Don’t Notice
You wrote the startup code:
sequelize.sync({ force: true });
app.listen(3000);
It runs every time the app starts.
Which means:
- App restarts → tables dropped
- App restarts → tables recreated
- App restarts → data erased
No crash.
No error.
No warning.
Just quiet obedience.
Tracing the Damage
Step by step:
- Server boots
- Sequelize connects to the database
- Existing tables are detected
-
force: truegives permission - Tables are dropped
- Tables are rebuilt from models
The data didn’t disappear.
It was replaced with emptiness.
When Each One Is Safe
Use sequelize.sync() when you want alignment —
when you want Sequelize to help, not decide.
Use sequelize.sync({ force: true }) only when:
- You are experimenting
- You expect total data loss
- You want a clean slate on purpose
And most importantly:
Never leave it where it can run again.
The Conclusion
ORMs feel gentle.
They feel protective.
They feel like they’re keeping you safe.
But every abstraction still sends real commands to real systems.
Databases don’t understand intention.
They only understand instructions.
It doesn’t guess what you mean.
It does exactly what you tell it to do.
Top comments (0)