Backend Development
Learn how our server-side code works with Next.js
The backend is where we process data, verify users, and talk to Firebase. Unlike traditional backends, we use Next.js for both frontend and backend — it's a full-stack framework.
Make sure you understand Prerequisites and Frontend first.
Backend Architecture
1. React Server Components
What: Server Components are React components that run on the server (not in the browser).
Why we use it: Server Components let us fetch data from Firebase before sending the page to the user. This makes pages load faster and reduces Firebase costs.
Key difference: By default, components in app/ are Server Components. Add 'use client' at the top to make them Client Components.
What to focus on:
- Server Components run on the server, Client Components run in the browser
- Server Components can directly access databases (Firebase) without API routes
- Use Client Components when you need interactivity (
useState,onClick, etc.) - Server Components are async by default — you can use
awaitdirectly
Example from our codebase:
Check src/app/team/page.tsx — here's how we fetch teams on the server:
// src/app/team/page.tsx
import { Team } from "@/app/types/team";
export default async function TeamPage() {
const teams = await Team.readAll({
server: true,
public: true
});
return <div>{/* render teams */}</div>;
}📚 Official Documentation:
Next.js — Server Components2. API Routes
What: API routes are server-side endpoints that handle HTTP requests (GET, POST, PUT, DELETE).
Why we use it: API routes let us create backend endpoints for actions like creating events, submitting applications, or verifying admin permissions.
Location: API routes live in src/app/api/ with a route.ts file.
What to focus on:
- How to create a
route.tsfile - Export functions named
GET,POST,PUT,DELETE - How to read request data (
request.json()) - How to return responses (
NextResponse.json())
Examples from our codebase:
Check src/app/api/ — here's an example API route structure:
// src/app/api/example/route.ts
import { NextResponse } from "next/server";
export async function GET() {
// Fetch data from Firebase
return NextResponse.json({ data: "..." });
}
export async function POST(request: Request) {
const body = await request.json();
// Process and save to Firebase
return NextResponse.json({ success: true });
}📚 Official Documentation:
Next.js — Route Handlers3. Middleware for Protected Routes
What: Middleware is code that runs before a request reaches your page or API route.
Why we use it: We use middleware to protect admin routes. It checks if the user is logged in and has admin permissions before allowing access.
Location: Our middleware is in src/middleware.ts
How it works:
- User visits
/admin - Middleware intercepts the request
- Checks Firebase Auth token from service worker
- Calls Firebase Cloud Function to verify admin status
- Either allows access or redirects to login
📚 Official Documentation:
Next.js — Middleware4. Edge Runtime
What: The Edge Runtime is a lightweight JavaScript environment that runs our backend code globally on servers close to users.
Why we use it: Instead of one server in one location, our backend runs on a global network (via Vercel). This makes our app fast for users anywhere in the world.
Important: The Edge Runtime has limitations — no file system, no sockets, limited Node.js APIs.
What you need to know:
- Our routes run on the Edge by default
- Can't use Node.js features like
fs(file system) - Can't use WebSockets or long-running processes
- Focus on stateless, fast request-response patterns
📚 Official Documentation:
Next.js — Edge and Node.js Runtimes5. Firebase Cloud Functions
What: Cloud Functions are serverless backend functions that run on Google's infrastructure.
Why we use it: Some operations need to run on Firebase's servers (like setting custom user claims for admin permissions). Cloud Functions let us do this securely.
Example: Our checkAdminClaims function verifies if a user is an admin.
When to use Cloud Functions:
- Setting custom user claims (admin status)
- Scheduled jobs (daily cleanup, email reminders)
- Database triggers (auto-update timestamps)
- Operations that require Firebase Admin SDK
📚 Official Documentation:
Firebase — Cloud Functions🎯 When to Use What
Use Server Components when:
- You need to fetch data before rendering a page
- You want to reduce client-side JavaScript
- The data doesn't need to be interactive
Use API Routes when:
- You need to handle form submissions
- You want a dedicated endpoint for client-side fetching
- You need to perform mutations (create, update, delete)
Use Firebase Cloud Functions when:
- You need Firebase Admin SDK features
- You want scheduled jobs or database triggers
- Operations must run on Firebase's infrastructure
📂 Where Backend Code Lives
src/app/api/ — API routes (route.ts files)
src/middleware.ts — Middleware for protected routes
src/app/types/ — Type classes with Firebase CRUD operations
functions/ — Firebase Cloud Functions (separate project)