Sequelize’s raw: true
: The Hidden Trap Behind Your Queries!
Sequelize is a powerful ORM for Node.js that simplifies working with databases. But if you’ve ever used the raw: true
option in Sequelize queries, you might have encountered unexpected results—especially when dealing with associations.
If you’ve ever wondered:
- Why does my related data disappear?
- Why is my association not an array anymore?
- Should I use
raw: true
for better performance?
This post will clear up the confusion and help you avoid hidden pitfalls when using raw: true
in Sequelize.
What Is raw: true
in Sequelize?
By default, Sequelize returns model instances when querying data. These instances come with useful ORM methods, but sometimes you may just want plain JavaScript objects.
When you use raw: true
, Sequelize skips its ORM layer and returns the raw query result as a plain object. This can improve performance in some cases, but it also changes how associations behave.
Let’s break this down with an example.
Case Study: Slot Game Bets and States
Imagine we’re building a slot game and tracking bets and their states. We have two models:
1. SlotGameBet (Main Bet Table)
const SlotGameBet = sequelize.define("SlotGameBet", {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
userId: DataTypes.INTEGER,
gameId: DataTypes.INTEGER,
});
2. SlotGameBetState (Tracks Bet Status Updates)
const SlotGameBetState = sequelize.define("SlotGameBetState", {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
slotGameBetId: DataTypes.INTEGER,
current: DataTypes.JSON,
next: DataTypes.JSON,
});
Relationship: One SlotGameBet has many SlotGameBetStates
SlotGameBet.hasMany(SlotGameBetState, { as: "betStates", foreignKey: "slotGameBetId" });
SlotGameBetState.belongsTo(SlotGameBet, { foreignKey: "slotGameBetId" });
Now, let’s query the latest bet for a user.
Scenario 1: Default Sequelize Query (No raw: true
)
const slotGameLastBet = await SlotGameBet.findOne({
where: { gameId, userId },
include: [{ model: SlotGameBetState, as: "betStates" }],
order: [["id", "DESC"]],
});
What Happens Here?
✅ Returns a Sequelize model instance with methods.
✅ betStates
is an array, even if there’s only one related record.
✅ You access data like this:
const firstBetState = slotGameLastBet.betStates?.[0];
console.log(firstBetState.next); // Works as expected
Scenario 2: Using raw: true
- What Changes?
const lastRound = await SlotGameBet.findOne({
where: { gameId, userId },
raw: true,
include: [{ model: SlotGameBetState, as: "betStates" }],
order: [["id", "DESC"]],
});
What Happens Now?
❌ No model instances — only plain JavaScript objects.
❌ betStates
is NOT an array anymore – it’s a single object!
❌ Methods like .get()
or .toJSON()
are gone.
Why Is My Association Not an Array Anymore?
When using raw: true
, Sequelize flattens the result. This means:
- If the SQL query returns multiple rows due to the JOIN, Sequelize does not group them into an array.
- Instead, it takes the first row and merges related data into a single object.
Unexpected Output:
{
id: 1,
userId: 123,
gameId: 10,
betStates: { id: 5, current: { ... }, next: { ... } } // Not an array!
}
Should You Use raw: true
?
✅ When to Use It:
✔️ If you don’t need Sequelize instance methods (e.g., .get()
, .toJSON()
).
✔️ When performance is critical, and you only need plain objects.
✔️ For lightweight queries where you don’t need associations.
❌ When to Avoid It:
❌ When using associations (since they won’t be arrays).
❌ If you need Sequelize’s data validation, virtual fields, or custom getters.
❌ When working with complex queries where raw: true
might flatten related data unexpectedly.
Final Thoughts
Sequelize’s raw: true
can be both powerful and dangerous. While it can improve performance, it can also break associations and return data in unexpected formats.
🔑 Key Takeaways:
- Sequelize default behavior → returns model instances, with associations as arrays.
raw: true
behavior → returns plain objects, with associations flattened (not arrays).- Solution: Wrap
betStates
manually as an array when usingraw: true
.
Next time you’re using Sequelize, be mindful of raw: true
—it might just be the hidden culprit behind your unexpected query results! 🚀