Architecture is the most consequential set of decisions you will make on any software project — and paradoxically, it is the decisions you make when you know the least. The tech stack, the data model, the deployment topology, the API surface: these choices compound over years, and changing them later costs orders of magnitude more than getting them right early.
This guide is not a theoretical overview of every architecture pattern ever invented. It is a pragmatic engineering guide based on building production platforms at GLYPHASH — from scholarly publishing systems with 600+ articles and complex editorial workflows to enterprise portals serving time-sensitive government data at sub-second speeds.
Why Architecture Matters
Software architecture is not about picking the "best" tools. It is about designing boundaries— where does one module end and another begin? Which components can change independently? What data flows through which pathways? These boundaries determine your team's velocity for the entire lifetime of the product.
A well-architected application is one where:
- Adding a new feature does not require modifying unrelated code
- A bug in one area does not cascade into system-wide failure
- Performance bottlenecks can be addressed without rewriting core systems
- New team members can understand the codebase within days, not weeks
Great architecture is invisible. You only notice it when it is wrong — when a simple feature requires changes across twelve files, or when a database query that should take milliseconds takes seconds because the data model was not designed for the access patterns you actually need.
The Three-Layer Model
Every web application, regardless of complexity, can be decomposed into three fundamental layers:
1. Presentation Layer (Client)
The user interface — everything the user sees and interacts with. In modern web architecture, this includes React components, CSS, client-side state management, and interaction handlers. With frameworks like Next.js, the presentation layer spans both server and client: Server Components render HTML on the server, while Client Components handle interactivity in the browser.
2. Business Logic Layer (Server)
The rules of your application — validation, authorization, data transformation, workflow orchestration. In a Next.js architecture, this lives in Server Actions, API routes, and server-side utility functions. This layer should be framework-agnostic — your business rules should not depend on Next.js, React, or any specific HTTP framework. They should be plain TypeScript functions that can be tested independently.
3. Data Layer (Persistence)
The database, file storage, and external service integrations. This layer handles data persistence, querying, caching, and consistency. In production, this typically means PostgreSQL for relational data, Redis for caching and sessions, and object storage (S3/Supabase Storage) for file uploads.
Monolith vs Microservices
This is the most over-debated question in modern software architecture, and the answer is simpler than the discourse suggests:
| Factor | Monolith | Microservices |
|---|---|---|
| Team Size | 1–15 developers | 15+ developers (multiple teams) |
| Deployment | Single deployable unit | Independent service deployment |
| Debugging | Stack traces, local debugging | Distributed tracing, log aggregation |
| Data Consistency | Database transactions | Eventual consistency, sagas |
| Latency | Function calls (nanoseconds) | Network calls (milliseconds) |
| Operational Overhead | Low | High (service mesh, orchestration) |
Start with a modular monolith. Organize your code by domain (users, billing, content, analytics) with clear interfaces between modules. When — and only when — a specific module genuinely needs independent scaling or a different deployment lifecycle, extract it into a service. This is the approach we take at GLYPHASH for every web application we build.
Serverless & Edge Computing
Serverless functions and edge computing represent the most significant shift in web architecture since containerization. Instead of provisioning and managing servers, you deploy functions that run on-demand — and with edge computing, those functions run in data centers closest to your users worldwide.
When Serverless Makes Sense
- API routes with variable traffic — Serverless functions scale to zero when idle and to thousands of instances under load. Perfect for webhook handlers, form submissions, and API endpoints.
- Edge middleware — Authentication checks, A/B testing, geo-based routing, and rate limiting at the CDN edge — before your application code even runs.
- Background jobs — Email sending, image processing, data aggregation. Functions that run in response to events, not HTTP requests.
When Serverless Does Not Make Sense
- Long-running processes — Most serverless platforms impose execution time limits (10-60 seconds). Video processing, ML model training, and large data imports need traditional compute.
- WebSocket connections — Serverless functions are stateless and short-lived. Persistent connections require dedicated infrastructure (Supabase Realtime, Pusher, dedicated servers).
- Heavy computation — Cold starts and memory limits make serverless unsuitable for CPU-intensive workloads.
Database Architecture
Your database is the foundation of your application. Choosing the right database — and designing the right schema — is arguably more important than choosing your framework.
PostgreSQL: The Default Choice
PostgreSQL is the correct default for almost every web application. It handles relational data, JSON documents, full-text search, vector embeddings (via pgvector), and real-time subscriptions (via Supabase Realtime). Before reaching for a specialized database, ask: "Can PostgreSQL do this?" The answer is usually yes.
Schema Design Principles
- Normalize first, denormalize later — Start with a properly normalized schema. Denormalize only when you have measured a specific query performance problem.
- Design for your queries — Your schema should make your most common queries simple and fast. If a query requires joining five tables, your schema might need restructuring.
- Use UUIDs for public identifiers — Sequential integer IDs leak information (order volume, user count). Use UUIDs for any identifier exposed in URLs or APIs.
- Add timestamps and soft deletes — Every table should have
created_at,updated_at, and ideallydeleted_atcolumns. Hard deletes in production data are almost always a mistake.
Caching Strategies
Caching is not an optimization — it is an architectural decisionthat affects data consistency, system complexity, and failure modes. Every cache is a contract: "this data may be stale by up to X seconds."
- ISR (Incremental Static Regeneration)— Next.js's built-in caching for pages. Serve static HTML with background revalidation. This is how OneStopRead achieves sub-second page loads for government job listings.
- CDN / Edge Caching — Cache API responses and static assets at the edge. Vercel, Cloudflare, and similar platforms handle this automatically for Next.js applications.
- Application-Level Cache — Redis or in-memory caching for expensive computations, database query results, or external API responses. Always set a TTL. Always have a cache invalidation strategy.
API Design Patterns
Modern web applications have multiple API surface areas:
- Server Actions — Next.js Server Actions for form mutations and data writes. Type-safe, no API endpoint boilerplate, progressive enhancement by default.
- REST API Routes — For external integrations, mobile apps, and third-party consumers. Keep REST endpoints versioned (
/api/v1/) and use consistent response shapes. - Webhooks — For receiving events from external services (Stripe, GitHub, Resend). Always verify webhook signatures and process events idempotently.
Architecture Decision Records
The most undervalued practice in software architecture is documenting why decisions were made. An Architecture Decision Record (ADR) is a short document that captures the context, the options considered, the decision, and the trade-offs accepted.
Six months from now, when someone asks "why did we use PostgreSQL instead of MongoDB?" or "why is authentication handled this way?" — the ADR provides the answer without anyone needing to reverse-engineer the reasoning from code.
Architecture is not a one-time decision. It is a continuous practice of evaluating trade-offs, documenting decisions, and evolving the system as requirements change. The best architects are not the ones who choose the perfect tools — they are the ones who design systems that can evolve.
If you are designing a web application and need architectural guidance — whether it is a greenfield platform, a system migration, or a performance overhaul — our team is ready to collaborate.