Node & Express ⚡ Recently updatedUpdated on Jun 30, 2026 — this content may still be evolving.
Node.js & Express Interview Questions
40+ questions with full answers. Practice out loud.
Question: What is Node.js and how does its architecture work?
Difficulty
🟢 Easy
Why Interviewers Ask This
They want to know you understand Node is not a language or framework — it’s a runtime.
Answer
Node.js is a JavaScript runtime built on Chrome’s V8 engine. It runs JS outside the browser using libuv for async I/O, an event loop, and a thread pool for blocking work. Single-threaded for JS execution, but handles concurrency via non-blocking I/O.
Example
// server.js
const http = require('http');
http.createServer((req, res) => res.end('OK')).listen(3000);
Follow-up Questions
- How does Node differ from browser JS?
- What is libuv?
- Is Node multi-threaded?
Common Mistakes
- Saying Node is multi-threaded for all JS code
- Confusing Node with Express
- Ignoring the event loop
Project Connection
Explain your API project as: V8 runs your JS, libuv handles sockets and disk I/O.
Question: Explain the Node.js event loop.
Difficulty
🟡 Medium
Why Interviewers Ask This
Core concurrency model — senior interviews dig here when APIs stall or CPU spikes.
Answer
The event loop processes callbacks in phases: timers, pending callbacks, idle/prepare, poll (I/O), check, close. Microtasks (promises, queueMicrotask) run between phases. Long synchronous CPU work blocks the entire loop.
Example
setTimeout(() => console.log('timer'), 0);
Promise.resolve().then(() => console.log('microtask'));
console.log('sync');
// sync, microtask, timer
Follow-up Questions
- What is the thread pool?
- process.nextTick vs setImmediate?
- How do you avoid blocking the loop?
Common Mistakes
- Thinking setTimeout(0) runs before promises
- Running heavy JSON parse on every request on main thread
- Using sync fs in production hot paths
Project Connection
If your Express server froze under load, mention checking for sync crypto or large loops on the main thread.
Question: How do CommonJS and ES modules work in Node?
Difficulty
🟡 Medium
Why Interviewers Ask This
Every real codebase picks a module system; mixing them wrong breaks builds.
Answer
CommonJS uses require/module.exports (default in older Node). ESM uses import/export; enable via .mjs or “type”: “module” in package.json. ESM is static, enables tree-shaking; CJS is dynamic require().
Example
// CommonJS
const fs = require('fs');
module.exports = { read: fs.readFile };
// ESM
import fs from 'fs';
export function read(p) { return fs.promises.readFile(p); }
Follow-up Questions
- Can you require ESM from CJS?
- What is __dirname in ESM?
- Dual package hazard?
Common Mistakes
- Using import in a .js file without type module
- Mixing default export styles
- Circular requires without refactoring
Project Connection
Match your project’s package.json type field when explaining how you structure routes and models.
Question: What is npm and how do package.json fields matter?
Difficulty
🟢 Easy
Why Interviewers Ask This
Daily tooling — they check you know dependencies vs devDependencies and scripts.
Answer
npm is Node’s package manager. package.json lists metadata, scripts, dependencies (^semver ranges), and engines. package-lock.json pins exact versions for reproducible installs.
Example
{
"scripts": { "start": "node server.js", "dev": "nodemon server.js" },
"dependencies": { "express": "^4.19.0" },
"devDependencies": { "jest": "^29.0.0" }
}
Follow-up Questions
- npm ci vs npm install?
- What does ^ mean?
- npx?
Common Mistakes
- Committing node_modules
- Using * for versions in production
- No lockfile in CI
Project Connection
Mention npm run dev and how lockfiles keep teammate machines consistent.
Question: What is Express and why is it used?
Difficulty
🟢 Easy
Why Interviewers Ask This
Baseline for backend Node roles — can you build HTTP APIs?
Answer
Express is a minimal web framework for Node. It wraps http.createServer with routing, middleware pipeline, and helpers for req/res. Unopinionated — you choose DB, auth, structure.
Example
const express = require('express');
const app = express();
app.get('/health', (req, res) => res.json({ ok: true }));
app.listen(3000);
Follow-up Questions
- Express vs Fastify?
- Is Express still relevant?
- What is app.use?
Common Mistakes
- Calling app.listen in every route file
- No error handling for async routes
- Huge monolithic app.js forever
Project Connection
Frame your REST API as Express routes + middleware + a data layer.
Question: What is middleware in Express?
Difficulty
🟡 Medium
Why Interviewers Ask This
Middleware is how auth, logging, and parsing compose — central to Express design.
Answer
Middleware functions have (req, res, next). They run in order; call next() to pass control or end the response. Types: application-level, router-level, error-handling (4 args), built-in, third-party.
Example
app.use(express.json());
app.use((req, res, next) => {
console.log(req.method, req.url);
next();
});
Follow-up Questions
- What if you forget next()?
- Order of middleware?
- Async middleware errors?
Common Mistakes
- Mounting auth after routes that need it
- Calling next() after res.send
- Not using error middleware
Project Connection
Describe a logging middleware you added before protected /api routes.
Question: How does routing work in Express?
Difficulty
🟢 Easy
Why Interviewers Ask This
REST design and clean URLs show up in every backend interview.
Answer
Routes map HTTP methods + paths to handlers. express.Router() groups routes. Path params (:id), optional chaining, and route-specific middleware keep APIs organized.
Example
const router = express.Router();
router.get('/users/:id', (req, res) => {
res.json({ id: req.params.id });
});
app.use('/api', router);
Follow-up Questions
- Route vs middleware?
- How to handle 404?
- app.all?
Common Mistakes
- Duplicate route paths with different methods unordered
- No API prefix versioning
- Fat handlers with DB + validation inline
Project Connection
Split users.routes.js and mount at /api/users — interviewers like modular structure.
Question: Explain the req and res objects in Express.
Difficulty
🟢 Easy
Why Interviewers Ask This
You must read input and send correct responses on real endpoints.
Answer
req carries method, url, headers, query (req.query), body (after parser), params. res sends responses: status(), json(), send(), set headers, cookies. Extended from Node’s http.IncomingMessage/ServerResponse.
Example
app.post('/items', (req, res) => {
const name = req.body.name;
res.status(201).json({ name });
});
Follow-up Questions
- req.body without middleware?
- Difference query vs params?
- res.locals?
Common Mistakes
- Not validating req.body
- Sending 200 for errors
- Leaking stack traces in res.json
Project Connection
Walk through POST /login reading email/password from body and returning JSON tokens.
Question: How do you design a REST API in Express?
Difficulty
🟡 Medium
Why Interviewers Ask This
Tests resource naming, HTTP verbs, and statelessness.
Answer
Use nouns for resources (/users, /users/:id), correct verbs (GET read, POST create, PUT/PATCH update, DELETE remove), consistent JSON, proper status codes, and versioning if needed. Keep handlers thin; delegate to services.
Example
// GET /api/users, POST /api/users, GET /api/users/:id
Follow-up Questions
- REST vs GraphQL?
- When is POST idempotent?
- HATEOAS?
Common Mistakes
- Verbs in URLs like /getUser
- Using GET to delete
- No pagination on lists
Project Connection
Map your project’s CRUD endpoints to REST verbs and explain why.
Question: Which HTTP status codes should a Node API return?
Difficulty
🟢 Easy
Why Interviewers Ask This
Wrong codes confuse clients and break monitoring.
Answer
Common: 200 OK, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable, 429 Too Many Requests, 500 Internal Server Error.
Example
if (!user) return res.status(404).json({ error: 'Not found' });
res.status(201).json(user);
Follow-up Questions
- 401 vs 403?
- When 204?
- 502 vs 503?
Common Mistakes
- Always 200 with { success: false }
- 500 for validation errors
- 404 for wrong auth
Project Connection
Audit one endpoint and justify each status code you’d return.
Question: How do you implement error-handling middleware in Express?
Difficulty
🟡 Medium
Why Interviewers Ask This
Unhandled errors crash requests or leak internals without a central handler.
Answer
Error middleware signature is (err, req, res, next) — four parameters. Place after routes. Sync errors need try/catch or wrappers; async errors must reach next(err) or use express-async-errors / wrapper.
Example
app.use((err, req, res, next) => {
console.error(err);
res.status(err.status || 500).json({ error: err.message });
});
Follow-up Questions
- Why 4 args?
- Handling unhandled promise rejections?
- Operational vs programmer errors?
Common Mistakes
- No error middleware at all
- Sending full err.stack in production
- Forgetting next(err) in async handlers
Project Connection
Show a global handler that logs internally but returns safe messages to clients.
Question: What does body-parser / express.json do?
Difficulty
🟢 Easy
Why Interviewers Ask This
POST/PUT APIs fail mysteriously without parsing middleware.
Answer
express.json() parses JSON bodies into req.body (built-in since Express 4.16). express.urlencoded() for forms. Set size limits to prevent huge payloads. Raw body needed for webhooks — use verify option.
Example
app.use(express.json({ limit: '100kb' }));
Follow-up Questions
- Content-Type requirements?
- multipart forms?
- Why limit body size?
Common Mistakes
- Parsing before routes that need raw body
- Trusting req.body without validation
- No limit — DoS risk
Project Connection
Mention validating JSON shape after parsing for your signup endpoint.
Question: How do you enable and configure CORS in Express?
Difficulty
🟡 Medium
Why Interviewers Ask This
Frontend on another origin will block API calls without CORS.
Answer
CORS is browser-enforced. Server sends Access-Control-Allow-Origin and related headers. Use cors package: cors() for dev, or whitelist origins in production. Preflight OPTIONS for non-simple requests.
Example
const cors = require('cors');
app.use(cors({ origin: 'https://myapp.com', credentials: true }));
Follow-up Questions
- Simple vs preflight?
- credentials with *?
- CORS on server-to-server?
Common Mistakes
- cors() wide open in production
- Forgetting credentials for cookies
- Only setting CORS on some routes
Project Connection
If React on localhost:5173 hits API on :3000, explain the headers you set.
Question: How do environment variables work in Node?
Difficulty
🟢 Easy
Why Interviewers Ask This
Secrets and config must not live in code — basic production hygiene.
Answer
process.env holds env vars set by the shell, Docker, or hosting platform. Never commit secrets. Use different values per environment (development, staging, production).
Example
const port = process.env.PORT || 3000;
Follow-up Questions
- 12-factor config?
- NODE_ENV?
- Validating env at startup?
Common Mistakes
- Hardcoding API keys
- No default for PORT locally
- Reading env inside tight loops unnecessarily
Project Connection
Describe PORT and DATABASE_URL coming from Railway/Render/Heroku-style hosting.
Question: What is dotenv and when should you use it?
Difficulty
🟢 Easy
Why Interviewers Ask This
Local dev ergonomics vs production injection.
Answer
dotenv loads .env into process.env at startup. Great for local development. In production, platforms inject env vars — don’t rely on .env files on disk. Add .env to .gitignore.
Example
require('dotenv').config();
const secret = process.env.JWT_SECRET;
Follow-up Questions
- dotenv in production?
- .env.example?
- Multiple env files?
Common Mistakes
- Committing .env
- Calling config() in every file
- No validation that JWT_SECRET exists
Project Connection
Show .env.example with placeholder keys for contributors.
Question: How does JWT authentication work in an Express API?
Difficulty
🟡 Medium
Why Interviewers Ask This
Stateless auth is standard for SPAs and mobile clients.
Answer
User logs in; server signs a JWT with a secret/private key containing claims (sub, exp). Client sends Authorization: Bearer
Example
const token = jwt.sign({ sub: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' });
// middleware: jwt.verify(token, secret)
Follow-up Questions
- JWT vs session cookie?
- Where to store tokens on client?
- Refresh tokens?
Common Mistakes
- Storing passwords in JWT
- No exp claim
- Using alg none attacks — verify alg
Project Connection
Explain login route issuing JWT and middleware protecting /api/profile.
Question: Why use bcrypt for passwords?
Difficulty
🟡 Medium
Why Interviewers Ask This
Storing plain or weakly hashed passwords is an instant fail.
Answer
bcrypt hashes passwords with a salt and adaptive cost factor (rounds). Slow by design to resist brute force. Compare with bcrypt.compare; never store plaintext or reversible encryption.
Example
const hash = await bcrypt.hash(password, 12);
const ok = await bcrypt.compare(password, hash);
Follow-up Questions
- bcrypt vs argon2?
- How many rounds?
- Pepper?
Common Mistakes
- MD5/SHA for passwords
- Same salt for all users manually wrong
- Logging passwords
Project Connection
Walk through register hashing and login compare in your auth flow.
Question: Sessions vs JWT — when to use which?
Difficulty
🟡 Medium
Why Interviewers Ask This
Architecture choice for auth — tradeoffs matter.
Answer
Sessions: server stores session state (memory/Redis), cookie holds session ID, easier revoke, more server state. JWT: stateless, scales horizontally, harder to revoke instantly, client holds token. SPAs often use JWT + refresh; traditional web apps often sessions.
Example
// session: req.session.userId = user.id
// JWT: Authorization header
Follow-up Questions
- Where to store session store?
- JWT revocation strategies?
- CSRF with cookies?
Common Mistakes
- JWT in localStorage ignoring XSS risk
- Huge JWT payloads
- Session without secure/httpOnly cookies
Project Connection
Pick what your project uses and defend it with one tradeoff.
Question: MongoDB and Mongoose basics for Node APIs.
Difficulty
🟡 Medium
Why Interviewers Ask This
Many Node jobs use document DBs — can you model and query?
Answer
MongoDB stores BSON documents. Mongoose adds schemas, validation, middleware, and models. Connect once at startup; use Model.find/create/update with async/await.
Example
const userSchema = new Schema({ email: { type: String, unique: true } });
const User = model('User', userSchema);
const users = await User.find().limit(10);
Follow-up Questions
- Embedded vs referenced docs?
- Indexes?
- Transactions?
Common Mistakes
- No schema validation
- N+1 populate queries
- Storing unbounded arrays in one doc
Project Connection
Describe one Mongoose model from your project and a typical query.
Question: SQL basics when using Node with PostgreSQL/MySQL.
Difficulty
🟡 Medium
Why Interviewers Ask This
Relational data and joins still dominate many backends.
Answer
Use parameterized queries to prevent injection. Tables, primary keys, foreign keys, JOINs. In Node use pg, mysql2, or an ORM (Prisma, Sequelize). Migrations version schema.
Example
const { rows } = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
Follow-up Questions
- ORM vs raw SQL?
- Migrations?
- Indexes for performance?
Common Mistakes
- String concatenation in SQL
- SELECT * in hot paths
- No connection pooling
Project Connection
Explain a users + orders relationship query you would run from Express.
Question: What is connection pooling and why use it?
Difficulty
🟡 Medium
Why Interviewers Ask This
Opening a DB connection per request does not scale.
Answer
A pool maintains reusable DB connections. Requests borrow a connection and return it. Limits max connections, reduces handshake overhead. pg Pool and mongoose connection are common patterns.
Example
const pool = new Pool({ max: 20, connectionString: process.env.DATABASE_URL });
Follow-up Questions
- Pool size tuning?
- What happens when pool exhausted?
- Serverless + DB?
Common Mistakes
- New connection every request
- Never closing pool on shutdown
- One global client with no limits
Project Connection
Mention pool max when discussing deployment under concurrent traffic.
Question: How does the MVC pattern apply to Express apps?
Difficulty
🟡 Medium
Why Interviewers Ask This
Shows you can structure code beyond a single app.js.
Answer
Model: data layer (Mongoose/Prisma). View: often JSON for APIs or templates for SSR. Controller: route handlers orchestrating request/response. Routes wire URLs to controllers.
Example
routes/ → controllers/ → services/ → models/
Follow-up Questions
- Service layer?
- Fat models?
- Where does validation live?
Common Mistakes
- Business logic only in routes
- Models importing Express
- Circular imports between layers
Project Connection
Draw your folder structure: routes, controllers, models.
Question: How do you validate request data in Express?
Difficulty
🟡 Medium
Why Interviewers Ask This
Bad input causes bugs, security issues, and 500s.
Answer
Validate body, query, and params with libraries like Zod, Joi, or express-validator. Fail fast with 400/422 and clear messages. Do not trust client input.
Example
const schema = z.object({ email: z.string().email() });
const body = schema.parse(req.body);
Follow-up Questions
- Validation vs sanitization?
- Where to validate — middleware?
- OpenAPI?
Common Mistakes
- Only frontend validation
- Generic ‘invalid’ errors
- Validating after DB call
Project Connection
Show validating registration fields before creating a user.
Question: How do you handle file uploads in Express?
Difficulty
🟡 Medium
Why Interviewers Ask This
Resumes, avatars, and CSV imports come up in product APIs.
Answer
Use multer or similar for multipart/form-data. Configure storage (disk, memory, S3). Enforce file size, MIME checks, and auth. Never execute uploaded files.
Example
const upload = multer({ limits: { fileSize: 2 * 1024 * 1024 } });
app.post('/avatar', upload.single('file'), handler);
Follow-up Questions
- Stream to S3?
- Virus scan?
- multipart without multer?
Common Mistakes
- No size limits
- Trusting client MIME type only
- Serving uploads from same origin without caution
Project Connection
Describe an avatar upload endpoint with size cap.
Question: What is streaming in Node and when use it?
Difficulty
🔴 Hard
Why Interviewers Ask This
Large files and real-time data need streams, not loading all into memory.
Answer
Streams process data in chunks via Readable, Writable, Duplex, Transform. pipe() connects them. Good for file download/upload, logs, video. Backpressure handled by stream API.
Example
fs.createReadStream('big.csv').pipe(res);
Follow-up Questions
- Backpressure?
- Stream vs buffer entire file?
- HTTP chunked encoding?
Common Mistakes
- Reading multi-GB file with readFileSync
- Ignoring stream errors
- No timeout on slow clients
Project Connection
Mention streaming a CSV export instead of building one giant string.
Question: What is the cluster module in Node?
Difficulty
🔴 Hard
Why Interviewers Ask This
Uses all CPU cores for HTTP servers on one machine.
Answer
cluster forks worker processes sharing a server port. Primary distributes connections; workers run Express. Does not replace horizontal scaling across machines.
Example
if (cluster.isPrimary) {
for (let i = 0; i < cpus().length; i++) cluster.fork();
} else {
require('./server');
}
Follow-up Questions
- cluster vs PM2?
- Sticky sessions?
- When not to use cluster?
Common Mistakes
- Cluster for CPU-heavy JS on one worker misunderstanding
- No process manager in prod
- Shared in-memory state across workers
Project Connection
Note PM2 cluster mode as production alternative.
Question: What are child processes in Node?
Difficulty
🟡 Medium
Why Interviewers Ask This
Offload CPU work or run CLI tools without blocking the event loop.
Answer
child_process.spawn/exec/fork runs separate processes. fork() has IPC channel. Use for image processing, ffmpeg, or isolated scripts — not for every request without pooling.
Example
const { spawn } = require('child_process');
const ls = spawn('ls', ['-la']);
Follow-up Questions
- worker_threads vs child_process?
- Security of user input in shell?
- fork IPC?
Common Mistakes
- exec with unsanitized user input
- Unbounded child spawns
- Ignoring exit codes
Project Connection
Example: spawning a worker script for PDF generation off the hot path.
Question: What are Buffers in Node?
Difficulty
🟡 Medium
Why Interviewers Ask This
Binary data — files, crypto, networks — lives in buffers.
Answer
Buffer is a fixed-length raw binary allocation (Uint8Array under the hood in modern Node). Used with fs, crypto, net. Encoding: utf8, hex, base64.
Example
const buf = Buffer.from('hello', 'utf8');
console.log(buf.toString('hex'));
Follow-up Questions
- Buffer vs TypedArray?
- Why not strings for binary?
- Alloc unsafe?
Common Mistakes
- Concatenating buffers in a loop inefficiently
- Assuming JSON for binary uploads
- Ignoring encoding
Project Connection
Tie to hashing passwords or reading file headers.
Question: How do the path and fs modules help in Node?
Difficulty
🟢 Easy
Why Interviewers Ask This
File paths and I/O are everyday backend tasks.
Answer
path joins segments safely cross-platform (path.join, resolve, basename). fs reads/writes files; prefer fs.promises or fs/promises over sync APIs in servers.
Example
const filePath = path.join(__dirname, 'data', 'config.json');
const data = await fs.promises.readFile(filePath, 'utf8');
Follow-up Questions
- path.join vs resolve?
- fs streams?
- __dirname in ESM?
Common Mistakes
- fs.readFileSync in request handler
- Manual string paths with .. bugs
- No error handling for missing files
Project Connection
Loading a JSON config at startup with path.join.
Question: How do you secure an Express API with Helmet and rate limiting?
Difficulty
🟡 Medium
Why Interviewers Ask This
Security headers and abuse prevention are expected in production APIs.
Answer
helmet sets HTTP headers (X-Content-Type-Options, CSP helpers, etc.). express-rate-limit caps requests per IP/window to reduce brute force and DoS. Combine with auth, validation, HTTPS.
Example
app.use(helmet());
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
Follow-up Questions
- Rate limit behind proxy?
- CSP breaking frontend?
- Distributed rate limits?
Common Mistakes
- Only helmet, no input validation
- Rate limit too loose on /login
- Trust proxy not set on Render/Heroku
Project Connection
List headers helmet adds and rate limit on auth routes.
Question: How should you approach logging in a Node API?
Difficulty
🟡 Medium
Why Interviewers Ask This
You cannot debug production without structured logs.
Answer
Use a logger (pino, winston) with levels (info, warn, error). Log request IDs, errors with context, not passwords. In production, ship logs to a aggregator. Morgan complements HTTP access logs.
Example
logger.info({ userId, route }, 'user login');
Follow-up Questions
- Structured vs console.log?
- PII in logs?
- Correlation IDs?
Common Mistakes
- console.log only
- Logging tokens/passwords
- No log rotation / volume control
Project Connection
Add request id middleware and log failed auth attempts.
Question: How do you test Express APIs?
Difficulty
🟡 Medium
Why Interviewers Ask This
Proves your endpoints behave — supertest is the common tool.
Answer
Use Jest/Vitest + supertest to hit app without listening on a port. Test status codes, JSON bodies, auth. Mock DB layer for unit tests; integration tests hit real test DB.
Example
const res = await request(app).get('/api/health').expect(200);
expect(res.body.ok).toBe(true);
Follow-up Questions
- Unit vs integration?
- Test databases?
- Coverage goals?
Common Mistakes
- Only manual Postman
- Tests sharing production DB
- No auth negative tests
Project Connection
Describe one supertest case for a protected route.
Question: What are deployment basics for a Node/Express app?
Difficulty
🟡 Medium
Why Interviewers Ask This
Can you ship code — process managers, env, health checks?
Answer
Set NODE_ENV=production, use process manager (PM2, Docker, platform). Listen on process.env.PORT. Health endpoint, graceful shutdown on SIGTERM, run migrations separately, monitor errors.
Example
process.on('SIGTERM', () => server.close(() => process.exit(0)));
Follow-up Questions
- Docker multi-stage?
- Zero-downtime deploy?
- Secrets management?
Common Mistakes
- node server.js in prod without restart policy
- No health check
- Running as root in container
Project Connection
Walk through deploying to Render/Railway/Fly with env vars.
Question: How does async programming work in Node?
Difficulty
🟡 Medium
Why Interviewers Ask This
Non-blocking I/O is why Node exists — callbacks, promises, async/await.
Answer
I/O operations are async: callbacks (legacy), Promises, async/await (syntactic sugar). await pauses the function, not the thread. Parallelism with Promise.all for independent tasks.
Example
const [user, posts] = await Promise.all([
User.findById(id),
Post.find({ userId: id }),
]);
Follow-up Questions
- Promise.all vs allSettled?
- Sequential await in loops?
- Error handling in async?
Common Mistakes
- await inside forEach (does not wait)
- Mixing callbacks and promises badly
- Unbounded parallel requests
Project Connection
Refactor callback-style fs to fs.promises in an example.
Question: What is callback hell and how do you avoid it?
Difficulty
🟢 Easy
Why Interviewers Ask This
Historical pain point — shows you know modern patterns.
Answer
Deep nested callbacks become unreadable and error-prone. Fix with modular functions, Promises, async/await, and centralized error handling.
Example
// avoid: getUser(id, (e,u) => getPosts(u, (e,p) => ...))
const user = await getUser(id);
const posts = await getPosts(user);
Follow-up Questions
- What is pyramid of doom?
- Error-first callbacks?
- util.promisify?
Common Mistakes
- Ignoring first err argument in callbacks
- Async await without try/catch
- Creating promise anti-patterns
Project Connection
Show before/after refactoring a nested DB callback chain.
Question: How do you prevent SQL injection in Node?
Difficulty
🟡 Medium
Why Interviewers Ask This
Critical security — parameterized queries are mandatory.
Answer
Never interpolate user input into SQL strings. Use placeholders ($1, ?) via pg/mysql2 or ORM. Validate types server-side. Least privilege DB users.
Example
// BAD: `SELECT * FROM users WHERE email = '${email}'`
await pool.query('SELECT * FROM users WHERE email = $1', [email]);
Follow-up Questions
- ORM always safe?
- Second-order injection?
- NoSQL injection?
Common Mistakes
- Raw SQL with template strings
- Trusting ORM without understanding
- DB user with superuser perms
Project Connection
Audit one query in your project for parameterization.
Question: How can XSS affect the backend and how do you mitigate?
Difficulty
🟡 Medium
Why Interviewers Ask This
XSS is often taught for frontend — backends store and reflect data too.
Answer
Stored XSS: malicious scripts saved via API and rendered in a client. Backend should validate/sanitize stored HTML, set Content-Type correctly, encode output in templates, use CSP headers. APIs returning user HTML are risky.
Example
// sanitize before save; JSON APIs usually escape on render in React
Follow-up Questions
- sanitize-html?
- JSON is not auto-safe in innerHTML
- Markdown rendering?
Common Mistakes
- Storing raw script tags from users
- text/html responses with user content
- No CSP
Project Connection
If your API returns bios rendered on a site, explain sanitization strategy.
Question: How do you implement pagination in APIs?
Difficulty
🟡 Medium
Why Interviewers Ask This
Listing endpoints without pagination break at scale.
Answer
Offset/limit (page, pageSize) simple but slow on large offsets. Cursor-based (after=id) scales better for feeds. Return metadata: total or nextCursor, items array.
Example
// GET /users?page=2&limit=20
const users = await User.find().skip((page-1)*limit).limit(limit);
Follow-up Questions
- Keyset pagination?
- Default limits?
- Sorting stability?
Common Mistakes
- No max limit (limit=999999)
- Inconsistent sort keys
- Offset on million-row tables
Project Connection
Add page/limit query params to your list users endpoint.
Question: How do you version a REST API?
Difficulty
🟡 Medium
Why Interviewers Ask This
Breaking changes without versioning break mobile apps and partners.
Answer
Version via URL (/api/v1/users), header (Accept-Version), or query. URL is clearest for many teams. Deprecate old versions with timeline and docs.
Example
app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);
Follow-up Questions
- Semantic versioning for APIs?
- Backward compatible changes?
- GraphQL versioning?
Common Mistakes
- Breaking changes without bump
- Two versions diverging same logic duplicated forever
- No deprecation headers
Project Connection
If you only have v1, explain how you’d add v2 for a renamed field.
Question: What is process.env.NODE_ENV used for?
Difficulty
🟢 Easy
Why Interviewers Ask This
Libraries change behavior based on environment — you should too.
Answer
NODE_ENV commonly ‘development’, ‘test’, or ‘production’. Express enables less verbose errors in production; some libs enable caching. Set explicitly in deployment — not a security boundary alone.
Example
if (process.env.NODE_ENV !== 'production') {
app.use(morgan('dev'));
}
Follow-up Questions
- Does webpack set it?
- production vs development errors?
- Other env vars?
Common Mistakes
- Relying on NODE_ENV for auth
- Undefined NODE_ENV in prod
- Different behavior not documented
Project Connection
Toggle detailed error stacks off in production in your error handler.
Question: What is the difference between libuv thread pool and worker threads?
Difficulty
🔴 Hard
Why Interviewers Ask This
Advanced but shows deep Node knowledge when discussing performance.
Answer
libuv thread pool (default 4) runs some blocking ops: fs, crypto, dns. Worker threads run JS in parallel for CPU tasks. Event loop stays on main thread per process.
Example
// UV_THREADPOOL_SIZE=8 for more pool threads
Follow-up Questions
- When does DNS use pool?
- crypto.pbkdf2 async?
- worker_threads use case?
Common Mistakes
- Confusing with cluster workers
- CPU work on main thread
- Huge thread pool without reason
Project Connection
Mention bcrypt async using thread pool under the hood.