Skip to content

Session 03

The Real Backend

Backend architecture, authentication, databases, infrastructure, and building systems that scale.


The Real Backend

Everything you’ve built so far has been frontend — what the user sees. The backend is the engine that powers it all. Let’s break it down.


What is a Backend?

A backend is a program that runs on a server (a computer somewhere on the internet) instead of in the user’s browser. It handles the things the frontend can’t or shouldn’t do on its own.

Frontend Backend
HTML, CSS, JavaScript Node.js, Python, Go, etc.
Runs in the browser Runs on a server
What the user sees Processes data, talks to databases
Can’t access databases directly Handles security and auth

Think of it like a restaurant: the frontend is the menu and the dining room. The backend is the kitchen — you don’t see it, but without it, nothing works.


What Does a Backend Actually Do?

1. Stores and retrieves data

When you sign up on a website, your email and password don’t just disappear — the backend saves them in a database. When you log in, the backend looks up your info and verifies it. Databases are structured storage: think of them as organized spreadsheets that can handle millions of rows instantly.

2. Handles authentication

Authentication is answering “who are you?” The backend manages signups, logins, password resets, and sessions. It never stores passwords in plain text — it hashes them (one-way encryption). When you log in, it compares the hash, not the actual password.

3. Processes business logic

“Can this user buy this item?” “Is the coupon still valid?” “What’s the total after discount and tax?” These calculations happen on the backend because you can’t trust the browser — users can manipulate anything sent from the frontend.

4. Connects to external services

Payment processing (Stripe), sending emails (SendGrid), file storage (AWS S3), third-party APIs — the backend acts as a secure bridge between your app and the outside world. You never want API keys exposed in frontend code.


01. Build a Simple Backend

Let’s create a basic backend server using Node.js and Express. This is the same JavaScript you already know — just running on a server instead of in a browser.

Step 1 — Create the project

$ mkdir my-backend && cd my-backend
$ npm init -y
$ npm install express

npm init -y creates a package.json file with defaults. npm install express adds the Express framework — the most popular way to build Node.js servers.

Step 2 — Create server.js

Create a file called server.js with this code:

const express = require("express");
const app = express();

app.get("/", (req, res) => {
  res.json({ message: "Hello from the backend!" });
});

app.listen(3000, () => {
  console.log("Server running on port 3000");
});
  • express() creates a server
  • app.get("/") defines what happens when someone visits the root URL
  • res.json() sends back JSON data
  • app.listen(3000) starts the server on port 3000

Step 3 — Run it

$ node server.js
Server running on port 3000

Open http://localhost:3000 in your browser. You should see: {"message": "Hello from the backend!"}


02. How Frontend and Backend Talk

Frontend and backend communicate through HTTP requests. The frontend sends a request, the backend processes it and sends back a response. This is the same protocol that powers the entire web.

Here’s what happens when a user signs up:

  1. User fills form, clicks Sign Up
  2. Frontend sends POST request to /api/auth/signup
  3. Backend validates the data (is email valid? is password strong enough?)
  4. Backend hashes the password and saves user to database
  5. Backend sends back a success response with a JWT token
  6. Frontend stores the token and redirects to dashboard

What is a JWT token?

A JSON Web Token is a way to prove “I am who I say I am” without sending the password every time. After login, the backend gives the frontend a signed token. The frontend includes this token in every subsequent request. The backend verifies the signature — if it’s valid, the user is authenticated.


03. Build a Full CRUD API

CRUD stands for Create, Read, Update, Delete — the four operations every backend needs. Let’s build a real one.

Full server.js

const express = require("express");
const app = express();
app.use(express.json());

const users = [];

app.get("/api/users", (req, res) => {
  res.json(users);
});

app.post("/api/users", (req, res) => {
  const { name, email } = req.body;
  if (!name || !email) {
    return res.status(400).json({ error: "Name and email are required" });
  }
  const user = { id: users.length + 1, name, email };
  users.push(user);
  res.status(201).json(user);
});

app.delete("/api/users/:id", (req, res) => {
  const id = parseInt(req.params.id);
  const index = users.findIndex((u) => u.id === id);
  if (index === -1) {
    return res.status(404).json({ error: "User not found" });
  }
  users.splice(index, 1);
  res.status(204).send();
});

app.listen(3000, () => {
  console.log("Server running on port 3000");
});

express.json() is middleware that parses JSON request bodies. Without it, req.body would be undefined.

Try it with curl

# Create a user
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice", "email": "alice@pdeu.ac.in"}'

# Get all users
curl http://localhost:3000/api/users

# Delete user with id 1
curl -X DELETE http://localhost:3000/api/users/1

Key patterns

  • :id in the route is a URL parameter — Express extracts it as req.params.id
  • req.body contains data sent in the request body (JSON, form data)
  • Always validate input before processing — never trust what the client sends
  • Use the correct status code: 201 for create, 204 for delete, 400 for bad input, 404 for not found

04. HTTP Status Codes

Every response has a status code that tells the frontend what happened. These are the ones you’ll use most:

2xx — Success

  • 200 OK — request succeeded
  • 201 Created — new resource made
  • 204 No Content — success, nothing to send back

4xx — Client Error

  • 400 Bad Request — missing or invalid data
  • 401 Unauthorized — not logged in
  • 404 Not Found — resource doesn’t exist

5xx — Server Error

500 Internal Server Error — something broke on the backend. This is always a bug in your code, not the client’s fault. Return this with a meaningful error message, never expose stack traces to users.


05. Your Skills Already Transfer

The backend isn’t a completely different world — it’s the same JavaScript, the same logic, running on a different machine.

JavaScript runs everywhere

The same JavaScript you used for the frontend runs on the backend with Node.js. Express.js, Fastify, NestJS — they’re all Node frameworks. You already know the language.

HTTP is the same language

Your frontend makes fetch() requests. The backend receives them with app.get() and app.post(). Same protocol, different side of the conversation.

TypeScript works on both sides

If you use TypeScript for frontend, you can use the exact same language for backend code — type safety across your entire stack.

Databases are just structured data

You already understand objects, arrays, and data structures. A database is a persistent, queryable version of the same thing. SQL is just asking questions about structured data.


06. Key Concepts to Know

REST APIs

A way to structure URLs so they’re predictable. GET /users gets all users, POST /users creates one, DELETE /users/5 removes user with ID 5. Most backends follow this pattern.

Databases

SQL databases (PostgreSQL, MySQL) store data in tables with rows and columns — great for structured data. NoSQL databases (MongoDB, Firebase) store data as documents — great for flexible, rapidly changing data. Start with SQLite for learning, PostgreSQL for production.

Environment Variables

Never hardcode secrets (API keys, database passwords) in your code. Use a .env file and load them with process.env.VARIABLE_NAME. Add .env to .gitignore so it never gets pushed to GitHub.

# .env
PORT=3000
DATABASE_URL=postgres://user:pass@localhost:5432/mydb
JWT_SECRET=my-super-secret-key

# in your code:
require("dotenv").config();
process.env.PORT // "3000"
process.env.JWT_SECRET // "my-super-secret-key"

Scalability

When your app gets popular, one server isn’t enough. Backends scale by adding more servers (horizontal scaling), caching frequent queries (Redis), and using queues for heavy tasks (Bull, RabbitMQ). The key is designing your code so it can scale when needed.


07. From Frontend to Full Stack

In Session 1, you built a frontend on Cloudflare Pages. To make it a full application, you’d add:

  • A Node.js server with Express to handle API requests
  • A database (SQLite for learning, PostgreSQL for production)
  • API routes that connect your frontend to your backend logic
  • Authentication — user accounts, sessions, and security

The full stack isn’t two separate things — it’s one system where the frontend and backend work together. You now understand both sides.


Key Takeaway

The backend isn’t magic — it’s the same JavaScript, the same logic, the same problem-solving you already practice. You’ve been thinking like an engineer since Session 1. Now you just need to learn where the server lives.