Modern JavaScript for Backend
The JavaScript patterns you'll use every single day in a Node.js backend. Master these and the rest becomes easy.
CommonJS vs ES Modules
Node.js supports two module systems. You need to know both because you'll encounter both:
CommonJS (CJS) — older
// Importing
const express = require('express');
const { Router } = require('express');
// Exporting
module.exports = { myFunc };
module.exports = myFunc;
ES Modules (ESM) — modern
// Importing
import express from 'express';
import { Router } from 'express';
// Exporting
export { myFunc };
export default myFunc;
Which to use?
Use ESM for new projects — add "type": "module" to package.json. Use CommonJS when working with older codebases or packages that don't support ESM yet. You'll recognise which is which by the import style.
async / await — The Backend Workhorse
Almost every backend operation is asynchronous — reading files, querying databases, calling external APIs. async/await makes this feel synchronous:
Callbacks (avoid)
fs.readFile('./data.json',
(err, data) => {
if (err) throw err;
db.save(data, (err2) => {
if (err2) throw err2;
// "callback hell"
});
});
async/await (use this)
async function saveData() {
const data = await fs.readFile(
'./data.json'
);
await db.save(data);
// linear, readable, same result
}
Error Handling with async/await
When an awaited Promise rejects, it throws — wrap in try/catch:
async function getUser(id) {
try {
const user = await db.users.findById(id);
if (!user) throw new Error('User not found');
return user;
} catch (err) {
// Log and re-throw, or return a safe default
console.error('getUser failed:', err.message);
throw err; // let the caller handle it
}
}
// Running multiple async operations in parallel
const [user, posts, comments] = await Promise.all([
db.users.findById(id),
db.posts.findByUser(id),
db.comments.findByUser(id),
]);
// All three queries run simultaneously — much faster than sequential awaits
Destructuring
// Object destructuring — extract named properties
const { name, email, age = 0 } = req.body; // age defaults to 0 if missing
// Rename while destructuring
const { id: userId } = req.params; // userId = req.params.id
// Array destructuring
const [first, second, ...rest] = items;
// In function parameters
function createUser({ name, email, role = 'user' }) {
// no need for req.body.name, req.body.email etc.
}
Spread & Rest
// Spread: expand an object or array
const updated = { ...existingUser, email: 'new@email.com' }; // merge/override
const allItems = [...list1, ...list2]; // merge arrays
// Rest: collect remaining args
function log(level, ...messages) { // messages is an array
console.log(`[${level}]`, ...messages);
}
Optional Chaining & Nullish Coalescing
// Optional chaining — safe navigation through possibly-null objects
const city = user?.address?.city; // undefined if user or address is null/undefined
const first = arr?.[0]; // safe array access
const result = fn?.(); // only calls if fn is defined
// Nullish coalescing — default only for null/undefined (not 0 or '')
const port = process.env.PORT ?? 3000; // use 3000 if PORT is unset
const name = user.name ?? 'Anonymous'; // not || which would catch '' too
Template Literals
// Multi-line strings and interpolation
const message = `
Hello ${user.name},
Your order #${order.id} has been ${order.status}.
Total: $${order.total.toFixed(2)}
`;
// Tagged templates (used by SQL libraries like Prisma)
const result = await sql`SELECT * FROM users WHERE id = ${userId}`;
// The library safely parameterises ${userId} — no SQL injection risk
Array Methods You'll Use Constantly
const users = [
{ id: 1, name: 'Alice', active: true },
{ id: 2, name: 'Bob', active: false },
{ id: 3, name: 'Carol', active: true },
];
users.filter(u => u.active); // [Alice, Carol]
users.map(u => ({ id: u.id, name: u.name })); // strip active field
users.find(u => u.id === 2); // Bob
users.some(u => !u.active); // true
users.every(u => u.active); // false
users.reduce((acc, u) => acc + (u.active ? 1 : 0), 0); // 2
🧠 Check Your Understanding
Go Deeper
Primary source: MDN — How to use Promises
Also read: javascript.info — async/await — the clearest deep-dive available.
Ask your teacher: "Show me how Promise.all differs from sequential awaits in terms of performance." or "What does ?? do that || doesn't?"