Skip to main content

The Problems Every Web Framework Is Trying to Solve

· 33 min read
Pere Pages
Software Engineer
Four different robotic machines, each in its own style, assembling the same puzzle pieces into a browser window; the pieces show a globe, a signpost, a screen, a database, a lightning bolt and a padlock

Next.js, Django, Spring Boot and Ruby on Rails look very different, but they answer the same small set of questions about how a web application works. This post maps those questions, so that you can recognise the problem before you learn one framework's answer to it.

Frameworks are answers to problems​

Imagine you are building an online store.

At first, the job looks simple. You need a page that lists the products, a page that shows the details of one product, and a shopping cart.

Very soon, questions appear:

  • How does the application know which page to show?
  • Where do the products come from?
  • How do you know which customer is which?
  • How do you stop one customer from seeing another customer's orders?
  • What happens when thousands of people visit the store at the same time?
  • You change the price of a product, but some customers still see the old price. Why?

None of these are questions about JavaScript. They are questions about web applications. Developers have answered them for decades, in Python, Java, PHP (PHP: Hypertext Preprocessor, a language made for web servers), Ruby, C#, JavaScript and many other languages.

Over time, developers noticed that they kept writing similar code to solve the same problems. That repeated code turned into web frameworks. A web framework is a set of rules, tools and ready-made building blocks that solves the problems every web application has, so you don't have to solve them again yourself.

Frameworks solve these problems in different ways, but the problems themselves are almost the same everywhere. That is why this post starts with the problems and not with any one framework. Once you can see the problem, moving from Next.js to Django, Laravel or Spring Boot gets much easier. You still have to learn a new language, its libraries and the framework's habits, but you don't have to learn how the web works again from the start.

What Next.js adds on top of React​

To see what a framework adds, it helps to look at one framework next to the library it is built on. Next.js and React are a good pair for this.

React is a library for building user interfaces. Its own documentation calls React "a JavaScript library for building interactive user interfaces" that "leaves it up to the developer where to use those functions in their application"[1]. React helps you describe what the user sees and how the screen changes when the data changes.

A complete web application needs much more than a screen. It needs addresses for its pages, a server, a way to read and save data, security, a way to avoid repeating slow work, error handling and a way to put it all online. React doesn't decide how you put those pieces together.

Next.js is built on React and makes many of those decisions for you. The same page describes Next.js as a framework that "handles the tooling and configuration needed for React, and provides additional structure, features, and optimizations"[1].

A few terms appear in the table below. A URL (Uniform Resource Locator) is the address of a page, like https://shop.example.com/products/42. Rendering means turning data into the HTML (HyperText Markup Language) that the browser draws on the screen. An endpoint is a URL that another program calls to get or send data, instead of a person reading a page.

ProblemWhat Next.js gives you
Which page answers a URL?Routing (the App Router)
Is the page rendered on the server or in the browser?Server rendering and browser rendering
How do we get the data?Ways to read data on the server
How do we avoid doing the same work again?A cache, and ways to refresh it
How do we create endpoints?Route Handlers
How do users send changes?Server Functions and Server Actions
How do we send images quickly?Image optimisation
How do we move between pages quickly?Navigation in the browser, and loading the next page early
How do we act on a request before it reaches a page?Proxy (called Middleware before Next.js 16)[2]
How do we build the application and put it online?A build step and links to hosting platforms

Next.js doesn't do everything. For example, it has no built-in database and no complete login system. Its own guide says its server features "are not a full backend replacement"[3]. Instead, it gives you a base to start from and clear places to connect the database, the login service and the other parts you choose.

This shows the most important idea in the whole post: a responsibility (a job the application must do) is different from an implementation (one particular tool that does that job).

  • Routing is a responsibility. The Next.js App Router is one implementation of it.
  • Caching is a responsibility. The Next.js cache functions are one implementation of it.
  • Storing data is a responsibility. PostgreSQL, MongoDB and SQLite are three implementations of it.

Every framework is a collection of implementations. If you learn the responsibilities, each new framework becomes a new set of tools for jobs you already know.

The most used web frameworks in 2026​

Next.js is only one member of a large family. Some frameworks focus on showing web pages. Others focus on building APIs (application programming interfaces: the endpoints that other programs call to read or change data). Others cover almost everything, from the database to login to the HTML.

The 2026 Stack Overflow Developer Survey asked developers: "Which web frameworks and web technologies have you done extensive development work in over the past year?"[4] The table below shows the answers for the application and backend frameworks. A backend is the part of an application that runs on the server, not in the browser. ASP.NET Core is Microsoft's web framework for the C# language (ASP stands for Active Server Pages).

RankFrameworkLanguageShare of people who answered
1Next.jsJavaScript / TypeScript20.6%
2ASP.NET CoreC#19.9%
3FastAPIPython18.5%
4ExpressJavaScript / TypeScript15.6%
5Spring BootJava / Kotlin12.8%
6FlaskPython12.5%
7DjangoPython11.3%
8LaravelPHP7.6%
9NestJSTypeScript5.8%
10Ruby on RailsRuby5.7%
11SvelteKitJavaScript / TypeScript5.6%
12NuxtJavaScript / TypeScript4.4%
13SymfonyPHP4.0%
14PhoenixElixir2.5%

Two other frameworks in the same survey are worth knowing: Astro (6.2%) and Axum, for the Rust language (3.6%).

How to read these numbers

The table leaves out three kinds of entries from the survey's list: libraries for building screens (like React, 41.5%), runtimes that run JavaScript on a server (like Node.js, 46.4%), and content management systems like WordPress. The numbers show what the people who answered the survey use. They are not an exact measure of what the whole world uses, and they don't say that two frameworks with similar numbers are built in a similar way.

Not every framework solves the same amount of the problem​

Frameworks come in three broad styles. The difference between them is how many decisions the framework makes for you.

  • Full-stack, integrated frameworks give you many building blocks and many rules. Next.js, Django, Rails, Laravel and Nuxt are examples.
  • Backend or API frameworks focus on the server side of the application. FastAPI, Spring Boot, ASP.NET Core and NestJS are examples.
  • Minimal frameworks give you a small base, and you choose the other tools yourself. Express and Flask are examples.

Read the diagram from left to right: the further right, the more the framework decides for you.

These groups are not strict. Spring Boot can send finished HTML pages, and Django can serve an API without any pages. Rails makes many decisions at the start. Express gives you more freedom, but also more work and more things to get right. Neither approach is better in every case.

What happens when someone opens a product page​

Before we look at the problems one by one, let's follow a single request.

A customer opens the online store and visits https://shop.example.com/products/42. The browser sends a request (a message asking for that page), and the server sends back a response (the page, or an error). Between those two moments, many parts of the system do a small job each.

This is a picture of the ideas, not a fixed order. For example, the login check can happen before routing, the cache can sit in several places, and a saved response can be sent back without the application running at all.

Still, almost every job a web application has appears in this one picture. A framework has to do each job, connect to a tool that does it, or leave you room to do it yourself. We can sort those jobs into eight areas.

The eight areas every web developer should understand​

The eight areas follow the path of the request above, from the network to running the application for real users.

Each area below starts with the problem, then lists the ideas that belong to it in a table. Every table has the same shape: the idea on the left, and the problem it solves on the right.

HTTP and networking: how computers talk​

Before a framework can do anything, the browser and the server must be able to talk to each other.

HTTP (Hypertext Transfer Protocol) is the set of rules for that conversation. It defines what a request and a response look like. The table also uses three other short names. DNS (Domain Name System) turns a name like shop.example.com into the number of a computer on the network. TLS (Transport Layer Security) encrypts the conversation, and it is the "S" in HTTPS. A CDN (content delivery network) is a group of servers spread around the world that keep copies of your content close to the users.

IdeaThe problem it solves
HTTP methodsTell the server whether you want to read, create, change or delete something
URLs and query parametersName the thing you want, and say which part of it you want
Request and response headersCarry extra information, such as the type of content or how long it can be cached
Status codesSay whether the request worked, failed, or moved somewhere else
CookiesLet the browser carry small pieces of information from one request to the next
DNSTurn a domain name into a network address
TLSEncrypt the data between the browser and the server
Connections and timeoutsLimit how long a request may take
ProxiesPass requests on, and maybe check, change or redirect them on the way
Reverse proxiesSit in front of the application servers and manage the incoming traffic
Load balancingShare the requests between several servers
CDNsSend content from a server close to the user

None of these ideas belong to a framework: the browser doesn't care whether the server is written in Python or in Java. Everything you learn here works the same in every framework.

Handling requests: how the application answers​

Once a request reaches the application, some code has to decide what to do with it.

The first step is routing: matching the URL and the HTTP method to a piece of code. Middleware is code that runs for many requests on their way in or out, for example to check a login or add a header. The rest of the table follows the request deeper into the application. JSON (JavaScript Object Notation), in the table, is the text format most APIs use to send data.

IdeaThe problem it solves
RoutingMatch the URL and the method of a request to the code that handles it
Route parametersTake values out of the URL, such as the product number 42
MiddlewareRun shared code for many requests
Request validationCheck that the incoming data has the expected shape and limits
Controllers and handlersOrganise the answer to one kind of request
Services and use casesHold the real business behaviour, such as "place an order"
API designDecide how other programs talk to the application
SerialisationTurn the application's data into a format like JSON
RedirectsTell the browser to ask for a different URL
RewritesSend the request to different code without changing the URL the user sees
Error handlingDeal with failures and send back a useful answer
Rate limitingLimit how often someone can make a request
IdempotencyMake sure that sending the same request twice doesn't do the work twice (for example, charging a card twice)
Background jobsDo slow work outside the request, so the user doesn't wait for it
WebhooksReceive messages from other systems when something happens there
Real-time communicationPush updates to the browser at once, with WebSockets or server-sent events

For example, when a customer places an order, the request handler might check the shopping cart, check that the customer may place the order, ask the order service to do the work, and send back the result.

This example shows a useful rule: receiving a request and applying the business rules are two different jobs. Many frameworks make it easy to put both in the same function. Keeping them apart usually makes the application easier to test and to change.

Rendering: how users see the result​

The application has the data. Now it has to turn that data into something a person can see. Next.js puts a lot of its effort into this area.

There are three main moments to build a page. With server-side rendering (SSR), the server builds the HTML when the request arrives. With client-side rendering (CSR), the browser builds or updates the page with JavaScript. With static site generation (SSG), the HTML is built once, before any request arrives, and then sent as a file. Hydration connects server rendering and browser rendering: the browser takes HTML that the server built and adds the JavaScript that makes the buttons and forms work.

The table also mentions CSS (Cascading Style Sheets, the files that describe how a page looks) and SEO (search engine optimisation: helping search engines find and understand your pages).

IdeaThe problem it solves
Server-side rendering (SSR)Build the HTML on the server for each request
Client-side rendering (CSR)Build or update the page in the browser
Static site generation (SSG)Build the HTML before any request arrives
HydrationAdd interactive behaviour to HTML that the server built
StreamingSend the page in parts, instead of waiting until all of it is ready
Templates and componentsReuse pieces of the page
LayoutsShare the same frame (header, menu, footer) between pages
Asset managementHandle the JavaScript, CSS, fonts and images
Bundling and compilingPrepare the code so the browser can run it
Code splittingSend only the code that the current page needs
PrefetchingLoad the next likely page before the user clicks
Pagination and infinite scrollingShow a long list in smaller parts
AccessibilityMake the page usable by people with different abilities
Localisation and internationalisationSupport several languages and regional formats, such as dates and prices
SEOHelp search engines find and understand the pages
Metadata and sitemapsDescribe the pages and list them for search engines
Progressive enhancementKeep the main features working when the extra JavaScript doesn't load

Not every framework renders pages itself. FastAPI, for example, is often used only to send JSON to a separate frontend (the part that runs in the browser). Rails, Django and Laravel usually build HTML on the server with templates. The job is the same. Only who does it changes: sometimes one framework, sometimes two technologies together.

Data and storage: how information is kept​

Most applications need to remember things. A shopping cart, an order or a customer's profile must still exist after the request is over.

Most of the ideas here are about a database, a program that stores data and finds it again quickly. A relational database stores data in tables that point at each other, and you talk to it in SQL (Structured Query Language). An ORM (object-relational mapping) lets you work with those tables as normal objects in your programming language, instead of writing SQL by hand.

IdeaThe problem it solves
DatabasesStore information and find it again later
Data modelsDescribe the things the application works with, and how they relate
SchemasFix the shape and the rules of the stored data
ORMWork with database tables as objects in your language
QueriesRead or change specific data
IndexesMake some searches in the database faster
RelationsConnect things, such as a customer and their orders
MigrationsChange the shape of the database safely as the needs change
TransactionsMake a group of changes succeed together or fail together
Connection poolingReuse database connections instead of opening a new one each time
Concurrency controlStop two changes at the same moment from breaking the data
Data consistencyDecide when other readers see a change
ReplicationKeep copies of the data, so it survives failures or serves more readers
Backups and recoveryGet the data back after a mistake or a failure
Object storageStore files such as images, documents and videos
Search indexingMake text search fast
Data retentionDecide how long information is kept

One distinction here is easy to miss: the way the business thinks about an order is not always the way the database stores it. The application might treat an Order as one thing with a customer, a list of products and a total price. The database might split that same order across three tables.

The business model says what an order means. The storage model says how it is saved. When you keep the two apart in your head, it becomes much easier to change the database, the ORM or even the whole backend framework.

Caching: how to avoid repeated work​

Suppose your store gets 10,000 requests for the same product page. Should the application ask the database 10,000 times? Usually not.

Caching means keeping a result you already computed, so the next request can reuse it instead of doing the work again. But caching brings a new problem: how do you know when the saved result is out of date? A saved result that is out of date is called stale.

This diagram shows one cache. A real application usually has several caches at once, and each one has its own rules about freshness.

The table uses TTL (time to live): the length of time a saved result may be reused before it counts as stale.

IdeaThe problem it solves
Browser cacheReuse files on the user's own device
CDN cacheReuse responses from a server close to the user
Server cacheAvoid repeating slow work on the server
Database query cacheAvoid running the same database query again
In-memory cacheGet often-used data very fast from memory, for example with Redis
Cache keysName each saved result, so the right one is reused
Cache invalidationRemove or mark results that can't be trusted any more
RevalidationCheck, or refresh, whether a saved result is still current
TTLLimit how long a saved result stays valid
Stale-while-revalidateSend the old result now, and refresh it in the background
Cache consistencyKeep the saved data close enough to the real data
Cache stampedesStop many requests at the same moment from rebuilding the same result
CompressionMake the data smaller before sending it
Lazy loadingWait to do work until it is really needed
Performance budgetsSet limits for speed, page size and resource use

A common mistake is to think of caching as one feature. In practice, caching is several layers, and each layer has its own rules about when its data goes stale. One application might keep pages at the CDN, API results on the server, database results in memory and images in the browser.

A product's price can be out of date in any of these layers. That is why the customer in the introduction could still see the old price after you changed it.

Security and identity: how to protect users​

Security is not one feature you install once and forget. It is many protections spread across the whole application.

Two words matter most here. Authentication checks who a user is. Authorisation checks what that user is allowed to do. The table also names several common attacks and standards:

  • CSRF (cross-site request forgery): another website tricks the user's browser into sending a request to your site, for example to change their email address.
  • XSS (cross-site scripting): an attacker gets their own JavaScript to run inside your page, in other users' browsers.
  • SQL injection: user input changes the meaning of a database query.
  • CORS (cross-origin resource sharing): browser rules that decide which other websites may read the responses from your server.
  • OAuth 2.0 (Open Authorization): a standard that lets one system give another system limited access, such as letting a printing service read your photos.
  • OpenID Connect: a layer on top of OAuth 2.0 that also tells the application who the user is. "Sign in with Google" uses it.
IdeaThe problem it solves
AuthenticationCheck who the user is
AuthorisationDecide what the user may do
SessionsRemember that a user is logged in, from one request to the next
TokensCarry proof of identity or of permission
Password hashingStore a check value for each password, never the password itself
OAuth 2.0Let one system give another limited access
OpenID ConnectAdd "who is this user" on top of OAuth 2.0
CSRF protectionBlock actions that another site starts without the user knowing
XSS protectionStop attackers' scripts from running in users' browsers
SQL injection protectionStop input from changing a database query
CORSControl which other websites may read your responses in the browser
Security headersTurn on the browser's own security rules
Input validation and output encodingLimit what untrusted input may contain, and show output safely
Secrets managementProtect passwords, keys and tokens that the application uses
EncryptionProtect data while it travels and, where needed, while it is stored
Access logsRecord sensitive actions and security events
Abuse protectionSlow down password guessing, bots and very large amounts of traffic
Dependency securityTrack and fix security holes in the libraries you use
Privacy and complianceHandle personal data as the law requires
Authentication and authorisation are not the same thing: knowing that a user is Alice doesn't mean Alice may read Bob's orders.

A framework may give you tools for authentication. Your application still has to apply its own access rules, because only your application knows that order 1234 belongs to Bob.

Architecture: how the code is organised​

As an application grows, the way you organise the code becomes as important as the code itself.

Without clear borders, database queries, screen logic, business rules and calls to other services get mixed together. Then a small change in one place breaks something in another. Architecture is the set of decisions about where each kind of code lives. The table uses three short names. MVC (model–view–controller) splits code into the data, the screen and the code that connects them. DDD (domain-driven design) organises the code around the business itself. A BFF (backend for frontend) is a small server built for one specific frontend, such as one mobile app.

IdeaThe problem it solves
LayersSeparate the screen, the business behaviour and the technical tools
Separation of concernsStop unrelated jobs from depending on each other
MVCOrganise code into data, screens and the code between them
Domain modellingDescribe the real-world things and rules of the business
DDDBuild the software around the business domain
Dependency injectionGive a piece of code the tools it needs, instead of letting it build them itself
RepositoriesHide how data is stored behind a simple interface
Service layersGroup the operations the application can do
Ports and adaptersKeep the core logic separate from databases, payment services and other outside tools
Modular architectureSplit the application into areas that each do one thing
MonolithsDeploy all the parts of the application together
MicroservicesSplit the parts into separate services that are deployed on their own
Event-driven architectureLet parts react to messages ("an order was placed") instead of calling each other
BFFGive one frontend a server made for its needs
API contracts and versionsKeep systems working together when one of them changes
Configuration managementChange settings for development, testing and production

For example, placing an order could pass through these layers:

This is a choice you make, not a rule that every framework forces on you. A small application might not need every layer, and a large one can gain a lot from them. The goal is not to add as many layers as possible: it is to change one part of the application without breaking the parts that have nothing to do with it.

Operations: how the application keeps working for real users​

An application that works on a developer's laptop is not yet ready for real users. It needs a reliable place to run, to receive traffic, to store data and to recover from failures. This is the area of production: the live system that real customers use.

The table uses CI/CD (continuous integration and continuous delivery): automatic steps that test, build and release the software every time the code changes. Observability means being able to see what the application is doing inside, from its logs, its numbers and its traces.

IdeaThe problem it solves
Web and application serversRun the code and answer the requests
Serverless functionsRun code without managing the servers yourself
Edge computingRun some code on servers close to the users
ContainersPackage the application together with everything it needs to run
CI/CDTest, build and release the software automatically
Environment configurationUse different settings for development, testing and production
Horizontal scalingAdd more copies of the application to handle more traffic
Vertical scalingGive one copy more memory or processing power
Stateless designLet any copy of the application handle any request
Queues and workersProcess slow tasks reliably, outside the request
SchedulingRun work at fixed times, such as every night
ObservabilityUnderstand what the application is doing inside
LoggingRecord events and details for finding problems
MetricsMeasure speed, errors, resource use and business activity
Distributed tracingFollow one request across several services
Health checksCheck whether a copy of the application can take traffic
Retries with backoffTry again after a short failure, waiting longer each time
Circuit breakersStop calling a service that keeps failing
Graceful degradationKeep the most important features working when one part fails
Disaster recoveryBring the service back after a major incident
Feature flagsTurn features on or off without a new release
RollbacksGo back to the last version that worked
Testing strategiesCheck that the code is correct at the unit, integration and end-to-end levels

The framework solves only a small part of this area by itself. Next.js gives you a way to build the application and put it online. How reliable the live system is depends on all the parts together: your hosting provider, your database, your CDN, your monitoring tools and the way you organised the code.

The same ideas in different frameworks​

Now we can come back to the idea from the start: the jobs stay the same, and only the tools change.

Suppose you have worked with Next.js for five years and you decide to learn Django. The code will look different, the rules will be different and the libraries will be different. But most of the jobs will be familiar, because you have already done them all in Next.js.

Here is the same job, "show product 42", in both frameworks. In Next.js, the folder name [id] is the route parameter, and the page reads it:

// app/products/[id]/page.tsx
export default async function ProductPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const product = await getProduct(id); // your own function that reads the database
return <h1>{product.name}</h1>;
}

In Django, a list of URL patterns does the routing, and a view function does the work:

# shop/urls.py
from django.urls import path
from . import views

urlpatterns = [
path("products/<int:product_id>/", views.product_detail),
]

# shop/views.py
from django.shortcuts import get_object_or_404, render
from .models import Product

def product_detail(request, product_id):
product = get_object_or_404(Product, pk=product_id)
return render(request, "shop/product_detail.html", {"product": product})

The two pieces of code share no syntax, but they do the same three jobs: take the number out of the URL, read the product from the database, and render a page. The table below lists more of these matches across four frameworks.

Some names in the table need a short explanation. Prisma and Drizzle are ORMs for TypeScript. Zod is a TypeScript library that checks the shape of data. JPA (Java Persistence API, now called Jakarta Persistence) is the standard way to map Java objects to database tables. Thymeleaf is a Java template engine for HTML. ERB (Embedded Ruby) is the Rails template format. Rack is the common interface between Ruby web servers and Ruby applications. Redis is a fast in-memory data store. Celery is a Python tool for background jobs. Flyway and Liquibase are tools that run database migrations.

JobNext.jsDjangoSpring BootRails
RoutingApp RouterURL dispatcherRequest mappingsRails Router
Handling a requestRoute HandlersViewsControllersControllers
MiddlewareProxy, plus other layersMiddlewareFilters and interceptorsRack middleware
Data modelsYour own types, plus an ORMDjango modelsJPA entitiesActive Record
Database accessPrisma, Drizzle or plain SQLDjango ORMSpring Data JPAActive Record
ValidationZod or your own codeForms and serializersBean ValidationActive Model validations
AuthenticationOutside libraries or servicesDjango authSpring SecurityBuilt-in generator or libraries
HTML renderingReact on the serverDjango templatesThymeleafERB views
CachingNext.js cache, or RedisCache framework, or RedisSpring Cache, or RedisRails cache
Background jobsOutside queues and workersCelery or similarSpring scheduling, Spring BatchActive Job
Database migrationsPrisma or a similar toolDjango migrationsFlyway or LiquibaseActive Record migrations

These are typical tools, not exact one-to-one matches. Django middleware and Next.js Proxy don't have the same abilities, and they don't run in the same place. Django models do several jobs at once, while a Next.js application might keep its business model and its storage model apart. The ideas still carry over.

What carries over when you change language​

When you move to a new framework, some of your knowledge comes with you and some doesn't. The table sorts the main kinds of knowledge into the two groups.

KnowledgeCarries over to a new framework?
HTTP and how the web worksYes
Routing as an ideaYes
Security principlesYes
Data modelling and transactionsYes
Caching and freshnessYes
ArchitectureYes
How deployment worksMostly
The framework's rules and habitsPartly
The language's syntax and behaviourNo
The framework's functions and librariesNo
Tools and deployment detailsNo

Most of the "Yes" rows are the eight areas from this post. Take dependency injection as an example. Once you understand why it exists, you recognise it in Spring Boot, in NestJS, or in a TypeScript application you wrote by hand. The way you write it changes. The reason you use it doesn't.

Every framework decision has a cost​

A framework is not just a list of features. It is a set of decisions, and every decision costs something. Three examples show the pattern.

Caching makes responses faster, but old data can be dangerous. A news article can be a minute out of date without harm. A bank balance can't. Server rendering sends useful HTML early, but it uses server resources for every request. Browser rendering allows very interactive pages, but the browser may have to download more code and data before the page is useful. A high-level ORM saves you from writing the same database code again and again, but it can hide a slow query behind a simple-looking line of code.

DecisionWhat you gainWhat it costs
Cache moreFaster responses, less load on the databaseUsers may see stale data
Render on the serverUseful HTML arrives earlyServer work for every request
Render in the browserVery interactive pagesMore code to download before the page is useful
Use a high-level ORMLess repeated database codeSlow queries are harder to spot

An experienced developer doesn't memorise which features exist: they understand which problem each feature solves, what it costs, and when to use it. That is why knowing a framework's functions is not the same as understanding the system.

What to learn, in order​

If you want to build this understanding step by step, follow the same path the request takes. Each step builds on the one before it.

  1. The base of the web: HTTP, DNS, TLS, browsers, servers and proxies.
  2. Handling requests: routing, middleware, headers, status codes, redirects and rewrites.
  3. Rendering: server rendering, browser rendering, static pages, hydration and streaming.
  4. Working with data: databases, models, schemas, queries, ORMs and migrations.
  5. Changing data safely: validation, transactions, changes at the same moment, and consistency.
  6. Caching: cache layers, invalidation, stale data and speed.
  7. Identity and security: authentication, authorisation, sessions, tokens and common attacks.
  8. Architecture: layers, domain models, services, repositories and dependencies.
  9. Communication between systems: APIs, background jobs, queues, webhooks and real-time updates.
  10. Production infrastructure: deployment, edge computing, scaling and reliability.
  11. Running the application: testing, logging, monitoring, tracing and recovering from incidents.
  12. Putting it all together: build the same application in Next.js, then compare it with another framework.

For each topic, ask the same four questions:

  1. What problem are we solving?
  2. Why does this problem exist?
  3. What are the common solutions, and what does each one cost?
  4. How do Next.js and other frameworks solve it?

These questions stop the learning from turning into a list of one framework's functions.

Frameworks change, the problems stay​

A developer who only knows how to use Next.js can build applications with Next.js. A developer who understands HTTP, routing, rendering, caching, data, security, architecture and operations can reason about any web application, in any language.

Frameworks change. Functions get new names, as Middleware became Proxy in Next.js 16. Libraries get replaced. The problems underneath change much more slowly, so learning them is the part of your knowledge that lasts.

References​

  1. Next.js, React Foundations: About React and Next.js
  2. Next.js documentation, Proxy
  3. Next.js documentation, How to use Next.js as a backend for your frontend
  4. Stack Overflow, 2026 Developer Survey: Web frameworks and technologies

Further reading: MDN (Mozilla Developer Network), HTTP for the networking area, and The Twelve-Factor App for the operations area.