What is the Modern Web Stack?
A decade ago, building a web application meant choosing between a handful of monolithic frameworks. Today, the landscape is both richer and more nuanced. The modern web stack is a carefully curated collection of tools, each chosen for its strengths, working together through well-defined interfaces.
Understanding these layers — what they do, why they exist, and how they connect — is the foundation of becoming an effective fullstack developer. Let's walk through each layer from the user's browser all the way down to the database.
The Frontend Layer
The frontend is everything the user sees and interacts with. In the modern stack, this means React components rendered by a framework like Next.js. The key insight is that modern frontends aren't just client-side anymore — they span both server and client.
// A Server Component — runs on the server, zero client JS
export default async function CoursePage() {
const courses = await db.select().from(coursesTable);
return (
<main className="max-w-4xl mx-auto">
{courses.map(course => (
<CourseCard key={course.id} course={course} />
))}
</main>
);
}The API Layer
The API layer handles data fetching, mutations, and business logic. With Next.js App Router, this layer is often implicit — Server Components fetch data directly, and Server Actions handle mutations without explicit API routes.
// app/api/courses/route.ts — when you need an explicit API
import { NextResponse } from 'next/server';
import { db } from '@/db';
import { courses } from '@/db/schema';
export async function GET() {
const allCourses = await db.select().from(courses);
return NextResponse.json(allCourses);
}The Database Layer
At the bottom of the stack sits your database — the source of truth for your application's data. PostgreSQL remains the gold standard for relational data, offering the perfect balance of reliability, features, and performance.
Modern ORMs like Drizzle provide type-safe database access that catches errors at compile time rather than runtime. This means fewer bugs, better developer experience, and code that's easier to refactor.
import { pgTable, text, serial, timestamp } from 'drizzle-orm/pg-core';
export const courses = pgTable('courses', {
id: serial('id').primaryKey(),
title: text('title').notNull(),
slug: text('slug').notNull().unique(),
description: text('description'),
createdAt: timestamp('created_at').defaultNow(),
});The Key Principle
The best modern stacks minimize the distance between your data and your UI. With Server Components + Drizzle, there's a direct line from database query to rendered HTML — no REST API, no state management library, no loading spinners.
Putting It All Together
| Layer | Technology | Role |
|---|---|---|
| UI Components | React 19 | Declarative, composable user interfaces |
| Framework | Next.js 15 | Routing, rendering, optimization |
| Styling | Tailwind CSS | Utility-first, responsive design |
| Database Access | Drizzle ORM | Type-safe queries and schema management |
| Database | PostgreSQL | Reliable, feature-rich data storage |
| Deployment | Vercel / Docker | Zero-config or containerized deployment |
This stack isn't just a collection of popular tools — it's a carefully designed system where each layer enhances the others. TypeScript provides the type safety glue that holds everything together, ensuring that a change in your database schema ripples through to your UI components with compile-time safety.
“The best technology stack is the one where every layer makes the other layers better. When your ORM generates types that your UI components consume, you've achieved fullstack type safety — and that changes everything.”