\n

Hang up… please wait, we're loading

Stage 3 of 7

Backend & APIs

Databases, authentication, REST APIs, Firebase, Node.js, and serverless — how the internet actually stores and secures your data.

~8 hours
Intermediate
Most Important Stage
Terminal Mode Active Nexray Stage 3: Backend & APIs — your interactive learning companion
Pro Tip

Backends live on servers — you talk to them via HTTP requests.

What Is a Backend?

GET /apiDB

What is Backend Development?

The backend is the engine room of your app — it processes requests, talks to databases, handles authentication, and sends data back to the browser.

  • Server receives HTTP requests
  • Logic processes data and auth
  • Database stores persistent data
  • Response sends JSON/HTML back

The frontend is what users see. The backend is the server-side code that stores data, handles authentication, runs business logic, and sends data to the frontend via APIs.

Frontend

Browser renders HTML/CSS/JS. Sends requests. Shows data from backend.

🔄
API

The bridge. Frontend calls API endpoints, backend processes and responds with JSON.

🗄️
Backend

Server code. Reads/writes database, validates data, handles auth, runs business logic.

🟢 Node.js + Express Setup

Node.js runs JavaScript on the server. Express is the most popular Node.js framework for building APIs.

BASH — Setup
# Create project folder
mkdir my-api && cd my-api

# Initialize Node.js project
npm init -y

# Install Express
npm install express

# Install dev tools
npm install -D nodemon  # auto-restart on file changes

# Add to package.json scripts:
# "dev": "nodemon server.js"

# Start dev server
npm run dev

Building a REST API

A REST API is a set of URL endpoints your frontend can call to create, read, update, and delete data (CRUD).

JavaScript — server.js (Express REST API)
const express = require('express');
const app = express();

// Middleware: parse JSON bodies
app.use(express.json());

// CORS: allow frontend to call this API
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  next();
});

// In-memory "database" (use a real DB in production)
let posts = [
  { id: 1, title: 'Hello World', author: 'Alice' },
  { id: 2, title: 'My Second Post', author: 'Bob' },
];

// GET all posts
app.get('/api/posts', (req, res) => {
  res.json({ success: true, data: posts });
});

// GET single post by ID
app.get('/api/posts/:id', (req, res) => {
  const post = posts.find(p => p.id === +req.params.id);
  if (!post) return res.status(404).json({ error: 'Not found' });
  res.json({ success: true, data: post });
});

// POST create a post
app.post('/api/posts', (req, res) => {
  const { title, author } = req.body;
  if (!title || !author) {
    return res.status(400).json({ error: 'title and author required' });
  }
  const newPost = { id: posts.length + 1, title, author };
  posts.push(newPost);
  res.status(201).json({ success: true, data: newPost });
});

// PUT update a post
app.put('/api/posts/:id', (req, res) => {
  const idx = posts.findIndex(p => p.id === +req.params.id);
  if (idx === -1) return res.status(404).json({ error: 'Not found' });
  posts[idx] = { ...posts[idx], ...req.body };
  res.json({ success: true, data: posts[idx] });
});

// DELETE a post
app.delete('/api/posts/:id', (req, res) => {
  posts = posts.filter(p => p.id !== +req.params.id);
  res.json({ success: true, message: 'Deleted' });
});

// Start server
app.listen(3000, () =>
  console.log(' API running at http://localhost:3000')
);

🗄️ Databases: SQL vs NoSQL

SQL (Relational)

Data in tables with rows & columns. Strict schema. Relationships via JOINs. Best for structured data.

Examples: PostgreSQL, MySQL, SQLite, PlanetScale
Use for: E-commerce, banking, user accounts with relations
NoSQL (Document)

Data as JSON documents. Flexible schema. Scales easily. Best for dynamic data.

Examples: Firebase Firestore, MongoDB, Supabase
Use for: Social apps, real-time data, rapid prototyping

Firebase Firestore

Firebase Firestore is Google's cloud NoSQL database. It's free to start, has real-time sync, and works directly from the browser — no backend server needed!

JavaScript — Firebase Firestore
// 1. Install Firebase SDK
// npm install firebase

import { initializeApp } from 'firebase/app';
import {
  getFirestore, collection, addDoc,
  getDocs, doc, updateDoc, deleteDoc,
  onSnapshot, query, where, orderBy
} from 'firebase/firestore';

// 2. Initialize (from Firebase Console → Project Settings)
const app = initializeApp({
  apiKey: process.env.VITE_FIREBASE_API_KEY,
  authDomain: 'your-app.firebaseapp.com',
  projectId: 'your-app-id',
});

const db = getFirestore(app);

// 3. Add a document
async function addPost(title, content) {
  const docRef = await addDoc(collection(db, 'posts'), {
    title,
    content,
    createdAt: new Date(),
    likes: 0
  });
  console.log('Added with ID:', docRef.id);
}

// 4. Get all documents
async function getPosts() {
  const snapshot = await getDocs(collection(db, 'posts'));
  return snapshot.docs.map(d => ({ id: d.id, ...d.data() }));
}

// 5. Real-time listener (auto-updates when data changes!)
onSnapshot(collection(db, 'posts'), (snapshot) => {
  const posts = snapshot.docs.map(d => ({ id: d.id, ...d.data() }));
  renderPosts(posts); // update your UI
});

// 6. Query with filters
const q = query(
  collection(db, 'posts'),
  where('likes', '>', 10),
  orderBy('createdAt', 'desc')
);

// 7. Update a document
await updateDoc(doc(db, 'posts', postId), { likes: 11 });

// 8. Delete a document
await deleteDoc(doc(db, 'posts', postId));

🔐 Authentication Concepts

Authentication = proving who you are. Authorization = what you're allowed to do. In 2026, the gold standard is using OAuth instead of storing passwords yourself.

🚨
NEVER store plain-text passwords
Always hash passwords with bcrypt before storing. Better yet, use Firebase Auth or Auth0 so you never touch passwords at all. Password leaks have ended companies. Don't roll your own crypto.

Firebase Auth (Google + Email)

Firebase AuthGoogle OAuth

Firebase Authentication

Firebase Auth lets you add secure sign-in to your app in minutes. Support Google, GitHub, email/password, and more — all with a few lines of code.

  • Google OAuth in 5 lines of JS
  • Email/password with verification
  • Persistent login across sessions
JavaScript — Firebase Authentication
import {
  getAuth, signInWithPopup, GoogleAuthProvider,
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  signOut, onAuthStateChanged
} from 'firebase/auth';

const auth     = getAuth(app);
const provider = new GoogleAuthProvider();

// === Google Sign-In (one-click!) ===
async function signInWithGoogle() {
  const result = await signInWithPopup(auth, provider);
  const user = result.user;
  console.log('Signed in as:', user.displayName, user.email);
  // user.uid = unique user ID, use this in Firestore
}

// === Email + Password Sign Up ===
async function signUp(email, password) {
  const userCredential = await
    createUserWithEmailAndPassword(auth, email, password);
  return userCredential.user;
}

// === Email + Password Login ===
async function login(email, password) {
  const { user } = await
    signInWithEmailAndPassword(auth, email, password);
  return user;
}

// === Sign Out ===
const logout = () => signOut(auth);

// === Listen to auth state (runs on every page) ===
onAuthStateChanged(auth, (user) => {
  if (user) {
    // User is logged in
    console.log('Logged in:', user.uid);
    document.getElementById('user-name').textContent = user.displayName;
    document.getElementById('login-btn').style.display = 'none';
    document.getElementById('logout-btn').style.display = 'block';
  } else {
    // User is logged out
    document.getElementById('login-btn').style.display = 'block';
  }
});

// === Firestore Security Rules ===
// In Firebase Console → Firestore → Rules:
// rules_version = '2';
// service cloud.firestore {
//   match /databases/{db}/documents {
//     match /posts/{id} {
//       allow read: if true;         // anyone can read
//       allow write: if request.auth != null; // only logged-in users
//     }
//   }
// }

OAuth Providers

OAuth lets users log in with existing accounts (Google, GitHub, Twitter). You never store their password — the provider handles it.

Firebase Auth Providers
Google (most popular)
GitHub
Apple (required for iOS apps)
Twitter / X
Microsoft
Phone (SMS OTP)
Alternative: Auth0 / Clerk

Clerk.com is the 2026 favorite for Next.js apps — beautiful pre-built UI, zero config, free tier.

BASH
npm install @clerk/nextjs

Serverless Functions

Serverless functions let you run backend code without managing a server. You pay only when the function runs (often free for small apps).

JavaScript — Vercel Serverless Function
// File: /api/send-email.js (Vercel auto-routes this)

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const { name, email, message } = req.body;

  // Send email with Resend.com (free 3000 emails/month)
  const response = await fetch('https://api.resend.com/emails', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.RESEND_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      from: 'noreply@yourdomain.com',
      to: 'you@yourdomain.com',
      subject: `New message from ${name}`,
      html: `<p><strong>From:</strong> ${email}</p><p>${message}</p>`
    })
  });

  if (!response.ok) {
    return res.status(500).json({ error: 'Email failed' });
  }

  res.json({ success: true, message: 'Email sent!' });
}

Environment Variables & Secrets

API keys and secrets must NEVER be in your frontend code or committed to git. Use environment variables.

.env — Environment Variables
# File: .env  (NEVER commit this to git!)
# Add ".env" to your .gitignore file

FIREBASE_API_KEY=AIzaSy...
FIREBASE_PROJECT_ID=my-app-123
RESEND_API_KEY=re_abc123...
STRIPE_SECRET_KEY=sk_live_...
DATABASE_URL=postgresql://user:pass@host/db

# In Node.js, access via:
# process.env.FIREBASE_API_KEY

# In Vite (frontend), prefix with VITE_:
# VITE_FIREBASE_API_KEY=...  →  import.meta.env.VITE_FIREBASE_API_KEY

## .gitignore — protect your secrets ##
node_modules/
.env
.env.local
.env.production
dist/
.DS_Store
⚠️
Production Secrets on Vercel/Netlify
Add secrets in your hosting dashboard: Vercel → Project Settings → Environment Variables. Netlify → Site Settings → Environment Variables. These are injected at build time and never exposed to users.

Stage 3 Project: Full-Stack Blog

Build a blog with:

Firebase Firestore to store posts
Google Sign-In authentication
Create/Read posts (only when logged in)
Real-time updates with onSnapshot
Firestore security rules protecting data
Deployed to Vercel with environment variables
PreviousStage 2 — Frontend Dev