Engineering
2026-05-15
15 min read

The Complete Backend Engineering Guide

Everything you need to crack a backend interview — from REST semantics to distributed systems, real-time architecture, and the tricky gotchas that separate great engineers from good ones

The Complete Backend Engineering Guide

Backend Engineering Fundamentals

Modern backend engineering is no longer just about building CRUD APIs. A production backend today handles distributed traffic, concurrent users, database consistency, background jobs, caching layers, security boundaries, real-time communication, observability, and failure recovery — all while remaining scalable, maintainable, and fast.

The challenge is not simply writing endpoints. The real challenge is understanding why backend systems are designed the way they are. Every architectural decision is a trade-off between performance, consistency, complexity, scalability, developer velocity, and operational cost.

A strong backend engineer does not memorize tools. They understand the problems those tools solve.

The Evolution: Node.js → Bun.js

Most backend engineers start with Node.js and Express. Modern production systems increasingly use Bun.js and frameworks like Elysia.js because they provide native TypeScript execution, faster startup times, lower memory usage, and higher throughput.

The concepts remain the same — HTTP, async programming, databases, caching, queues — but the runtime primitives and ecosystem evolve.

// Node.js + Express
const express = require('express');
require('dotenv').config();

// Bun.js + Elysia.js
import { Elysia } from 'elysia';

const app = new Elysia();

const secret = Bun.env.JWT_SECRET;

Bun removes many layers traditionally required in Node.js:

  • No ts-node
  • No Babel configuration
  • No separate dotenv loader
  • Native package manager + runtime

The runtime becomes simpler, faster, and more integrated.

---

HTTP & REST Fundamentals

Backend systems communicate primarily over HTTP. Understanding HTTP deeply is foundational because every API, browser request, mobile request, and microservice interaction depends on it.

HTTP Methods

Each HTTP method carries semantic meaning.

GET     → Fetch data
POST    → Create new data
PUT     → Replace entire resource
PATCH   → Partial update
DELETE  → Remove resource

The critical concept here is idempotency.

An operation is idempotent if calling it multiple times produces the same result.

GET /users/1
GET /users/1
GET /users/1

No matter how many times this runs, the resource does not change.

PUT is also idempotent:

PUT /users/1
{
  "name": "John"
}

Calling it once or ten times leaves the resource in the same state.

POST is NOT idempotent:

POST /payments

Retrying may create duplicate payments.

This distinction matters enormously in distributed systems where retries happen automatically.

---

REST Principles

REST is not merely “JSON over HTTP.” It is an architectural style based on constraints.

1. Statelessness

Every request contains all information needed to process it.

The server should not rely on in-memory session state.

This enables horizontal scaling because any server instance can process any request.

2. Resource-Oriented Design

Resources are nouns, not verbs.

// Good
GET /orders
POST /orders

// Bad
GET /getOrders
POST /createOrder

3. Uniform Interface

Clients interact consistently with resources regardless of implementation details.

4. HATEOAS

Responses can include discoverable links.

{
  "id": 101,
  "status": "pending",
  "links": {
    "cancel": "/orders/101/cancel"
  }
}
---

Status Codes

Status codes communicate the result of a request.

2xx — Success

200 OK
201 Created
204 No Content

4xx — Client Errors

400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
409 Conflict
422 Unprocessable Entity
429 Too Many Requests

5xx — Server Errors

500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout

Strong backend engineers know when each status code should be used — not just what they mean.

---

Middleware & Request Pipelines

Middleware forms the backbone of backend request processing.

A request typically flows through authentication, validation, rate limiting, logging, business logic, and response formatting.

app
  .onRequest(authMiddleware)
  .beforeHandle(validateInput)
  .get('/users/:id', handler)
  .afterHandle(logResponse);

Execution order matters.

Authentication must happen before authorization. Validation must happen before database writes.

Middleware architecture enables separation of concerns.

---

Async Programming & The Event Loop

JavaScript runtimes like Node.js and Bun are single-threaded. Concurrency is achieved through the event loop.

The Event Loop

The execution order is:

Call Stack
↓
Microtask Queue (Promises)
↓
Macrotask Queue (setTimeout, setInterval)
console.log("1");

setTimeout(() => console.log("2"), 0);

Promise.resolve().then(() => console.log("3"));

console.log("4");

Output:

1
4
3
2

Promises execute before timers because microtasks have higher priority.

---

Event Loop Blocking

The most dangerous mistake in Node.js/Bun is CPU-bound work on the main thread.

const huge = JSON.parse(bigPayload);

A 50MB parse operation can freeze the event loop for hundreds of milliseconds.

During that time:

  • No requests are processed
  • No sockets respond
  • No timers fire
  • The server appears “down”

Solutions

  • Worker Threads
  • Streaming parsers
  • Payload limits
  • Background job processing
---

Database Fundamentals

Databases are the persistence layer of backend systems.

SQL vs NoSQL

SQL Databases

  • Structured schema
  • ACID guarantees
  • Joins & relationships
  • Strong consistency

Examples:

  • PostgreSQL
  • MySQL

NoSQL Databases

  • Flexible schema
  • Horizontal scalability
  • Eventual consistency
  • High write throughput

Examples:

  • MongoDB
  • Cassandra
  • DynamoDB

The key engineering skill is knowing when to use which.

---

Indexes

An index is a sorted structure enabling fast lookups.

Without an index:

SELECT * FROM users WHERE email = 'a@b.com';

The database scans the entire table.

With an index:

CREATE INDEX idx_users_email ON users(email);

The lookup becomes logarithmic.

Indexes speed reads but slow writes because every insert/update must also update the index.

---

Composite Indexes

One of the most important real-world optimization techniques.

SELECT *
FROM orders
WHERE user_id = 42
ORDER BY created_at DESC
LIMIT 20;

On a 500M row table, this becomes extremely slow without the right index.

The Fix

CREATE INDEX idx_orders_user_created
ON orders(user_id, created_at DESC);

This allows efficient filtering and sorting simultaneously.

---

Transactions & ACID

Transactions guarantee consistency.

ACID

  • Atomicity → All or nothing
  • Consistency → Valid state transitions
  • Isolation → Concurrent safety
  • Durability → Persisted after commit
BEGIN;

UPDATE accounts
SET balance = balance - 100
WHERE id = 1;

UPDATE accounts
SET balance = balance + 100
WHERE id = 2;

COMMIT;

If the second update fails, the first rolls back.

---

Redis & Caching

Redis is an in-memory data store commonly used for:

  • Caching
  • Pub/Sub
  • Rate limiting
  • Queues
  • Session storage

Cache-Aside Pattern

async function getUser(id: string) {
  const cached = await redis.get(`user:${id}`);

  if (cached) {
    return JSON.parse(cached);
  }

  const user = await db.users.findById(id);

  await redis.set(
    `user:${id}`,
    JSON.stringify(user),
    'EX',
    300
  );

  return user;
}
---

The Thundering Herd Problem

Suppose a cache key expires.

10,000 requests suddenly hit the database simultaneously.

The database collapses.

Solutions

  • Cache locking
  • Jittered TTLs
  • Stale-while-revalidate
  • Probabilistic early expiration
---

Kafka & Distributed Messaging

Kafka is a distributed event streaming platform.

It is designed for:

  • High throughput
  • Fault tolerance
  • Event-driven systems
  • Asynchronous processing

Core Concepts

  • Topic → Stream of events
  • Partition → Parallelism unit
  • Offset → Consumer position
  • Consumer Group → Shared processing
Producer → Topic → Partition → Consumer Group
---

At-Least-Once Delivery

Kafka may redeliver messages after failures.

Consumers MUST be idempotent.

INSERT INTO payments(idempotency_key)
VALUES ('abc123')
ON CONFLICT DO NOTHING;

This prevents duplicate processing.

---

Background Jobs with BullMQ

Heavy or delayed work should not block HTTP requests.

Use queues.

await queue.add(
  'send-email',
  {
    to: 'user@example.com'
  },
  {
    attempts: 5,
    backoff: {
      type: 'exponential',
      delay: 1000
    }
  }
);

Typical background tasks:

  • Email sending
  • Video processing
  • Image compression
  • PDF generation
  • Analytics aggregation
---

Authentication & JWT

Authentication answers:

Who are you?

Authorization answers:

What can you do?

JWT Structure

Header.Payload.Signature

JWTs are signed, not encrypted.

The JWT Revocation Problem

JWTs are stateless.

If a user logs out, the token still works until expiry.

Solutions

  • Short access token lifetime
  • Refresh token rotation
  • Redis blocklists
  • Opaque session tokens
---

Rate Limiting

Rate limiting protects systems from abuse and overload.

Token Bucket

Requests consume tokens.

Tokens refill gradually over time.

Capacity: 100 tokens
Refill: 10 tokens/sec

If the bucket empties, requests are rejected.

---

WebSockets & Real-Time Systems

HTTP is request-response.

WebSockets enable persistent bidirectional communication.

Handshake

Upgrade: websocket
Connection: Upgrade

The server replies:

101 Switching Protocols

A persistent TCP connection is established.

---

Scaling WebSockets

In-memory pub/sub fails across multiple servers.

Solution

Redis Pub/Sub.

Server A → Redis → Server B

This enables horizontal scaling.

---

FFmpeg & Media Pipelines

Media processing is CPU-intensive and asynchronous.

Transcoding vs Transmuxing

Transcoding

  • Re-encodes video
  • Changes codec
  • CPU expensive

Transmuxing

  • Changes container only
  • No quality loss
  • Very fast
---

HLS Streaming

Large videos are split into segments.

video.m3u8
segment1.ts
segment2.ts
segment3.ts

The player adapts quality dynamically based on bandwidth.

---

System Design Thinking

System design interviews evaluate reasoning, not memorization.

What Strong Engineers Do

  • Ask clarifying questions
  • Estimate scale
  • Identify bottlenecks
  • Discuss trade-offs
  • Consider failure modes
  • Design for observability
---

Designing Uber

The challenge is not maps.

The challenge is coordinating millions of moving entities in real time.

Core Components

  • Geo-search for nearby drivers
  • WebSocket location streams
  • Trip state machine
  • Surge pricing engine
  • Payment idempotency
  • Kafka event streams

Important Trade-Off

For driver locations:

Availability > Consistency

Slightly stale location data is acceptable.

Total outage is not.

---

Observability

Production systems fail.

Observability determines how quickly you recover.

The Three Pillars

1. Logs

{
  "level": "error",
  "requestId": "abc123",
  "message": "Payment failed"
}

2. Metrics

  • Latency
  • Error rate
  • CPU
  • Memory

3. Tracing

Distributed tracing follows requests across services.

API Gateway
→ Auth Service
→ Payment Service
→ Notification Service

Without tracing, debugging distributed systems becomes nearly impossible.

---

Graceful Shutdown

Containers and orchestration systems terminate processes constantly.

A production backend must shut down safely.

process.on('SIGTERM', async () => {
  await server.stopAcceptingConnections();
  await queue.close();
  await database.close();
  process.exit(0);
});

Without graceful shutdown:

  • Requests are dropped
  • Jobs are lost
  • Data becomes inconsistent
---

Final Thought

Backend engineering is ultimately about building systems that continue working under stress, failure, scale, concurrency, and unpredictable real-world conditions.

Frameworks change.

Languages evolve.

Infrastructure shifts.

But the core engineering principles remain constant:

  • Design for failure
  • Understand trade-offs
  • Measure bottlenecks
  • Prefer simplicity
  • Build observable systems
  • Optimize only after measurement

The best backend engineers are not the ones who memorize technologies. They are the ones who understand the reasoning beneath them.

That is what separates someone who can build APIs from someone who can build systems.

Share
Deephang Thegim

Deephang Thegim

Your Friendly Neighborhood