DEV Community

Cover image for 7 Node.js Mistakes That Are Quietly Killing Your Backend
Akash Gupta
Akash Gupta

Posted on

7 Node.js Mistakes That Are Quietly Killing Your Backend

7 Node.js Mistakes That Are Quietly Killing Your Backend

Your API works. It passes the demo. Then it hits real traffic — and everything slows to a crawl, memory balloons, and one bad request takes the whole thing down.

Most of the time it's not a hard bug. It's one of these seven quiet mistakes almost every backend developer makes early on. Fix them and your Node.js backend gets faster, safer, and far harder to knock over.

1. Blocking the event loop

Node is single-threaded for your code. One synchronous, heavy operation freezes every request, not just the current one.

// ❌ blocks everyone while it runs
const hash = crypto.pbkdf2Sync(password, salt, 100000, 64, 'sha512')

// ✅ async version keeps the loop free
crypto.pbkdf2(password, salt, 100000, 64, 'sha512', (err, hash) => { /* ... */ })
Enter fullscreen mode Exit fullscreen mode

Rule of thumb: if a function ends in Sync, ask what it's blocking. JSON.parse on a huge payload, big loops, synchronous file reads — same danger.

2. Not handling promise rejections

An unhandled rejection can crash the whole process in modern Node.

// ❌ if this throws, nothing catches it
app.get('/user', async (req, res) => {
  const user = await db.findUser(req.query.id)
  res.json(user)
})

// ✅ wrap async handlers so errors reach your error middleware
const wrap = fn => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next)
app.get('/user', wrap(async (req, res) => {
  const user = await db.findUser(req.query.id)
  res.json(user)
}))
Enter fullscreen mode Exit fullscreen mode

3. No database indexes

Your query is fast on 100 rows and dies on 100,000. Without an index, the database scans every single document.

If a query filters or sorts on a field, that field almost always needs an index. One line often turns a 900ms query into a 3ms one. Check your slow queries before users find them for you.

4. Trusting user input

Every value from the client is hostile until proven otherwise. Unvalidated input is how you get injection, crashes, and garbage in your database.

Validate the shape and type of every request body and query param at the edge (a schema validator makes this one line per route). Never build a database query by string-concatenating user input.

5. Leaking secrets and stack traces

Two classics: committing a .env file, and sending raw error objects to the client.

// ❌ hands attackers your stack trace, file paths, and query internals
res.status(500).json({ error: err })

// ✅ log the detail, return something safe
console.error(err)          // or your error tracker
res.status(500).json({ message: 'Something went wrong' })
Enter fullscreen mode Exit fullscreen mode

Keep secrets in environment variables, never in the repo. Add .env to .gitignore before your first commit.

6. No timeouts on outbound calls

Calling another API or service with no timeout means one slow dependency can hang your requests forever and pile up until you run out of connections.

Always set a timeout on outbound HTTP calls and database operations. Fail fast, return a clear error, and your backend stays responsive even when something downstream is having a bad day.

7. Console.log as your only observability

console.log is fine for local dev. In production it tells you nothing when a real user hits a bug at 2 AM and you're asleep.

Use structured logging and an error tracker that alerts you the moment something breaks — with the stack trace and the request that caused it. The goal: you find the bug before your users report it.


The pattern behind all seven

Every one of these is the same lesson: code that works in a demo is not code that survives production. The gap between "it runs" and "it holds up under real load, real users, and real attackers" is exactly what separates a hobby project from a hireable backend developer.

None of this is advanced. It's just rarely taught in order — which is why so many devs learn it the painful way, in production.

I run AS Backend Institute, where we teach backend and full-stack development the way it actually works in production — not just tutorials that stop at "hello world." If you want a structured path, start here.

If this saved you one 2 AM incident, share it with a developer who's still doing console.log in production. 🙂

Top comments (0)