Last modified: April 27, 2026
This article is written in: 🇺🇸
Web servers deliver two main types of content: static and dynamic. Static content usually consists of files such as HTML, CSS, images, videos, and JavaScript bundles that already exist on the server. These files are served directly to the client without needing extra processing.
Dynamic content is generated at request time. It may depend on the current user, database records, session state, permissions, location, time, or other changing conditions. A dynamic page or API response is built by application logic before it is returned to the client.
Static content is pre-generated and served “as is” from the server. The server does not need to run application code, query a database, or customize the response for each user. It simply finds the requested file and sends it back.
Because static content is usually predictable and does not change often, it can be cached aggressively. Browsers, CDNs, and reverse proxies can store static files and reuse them for later requests. This makes static content very efficient to serve at scale.
Common examples include HTML files, images, videos, CSS stylesheets, fonts, and JavaScript files.
Static content includes files that are already created before the request arrives.
Example static file request:
GET /styles/main.css HTTP/1.1
Host: example.com
Example output:
body {
font-family: Arial, sans-serif;
background: #f5f5f5;
}
The server returns the CSS file exactly as stored. No database query or user-specific rendering is required.
Static serving is usually straightforward. The client requests a file, the server looks for that file on disk or in memory cache, and the server returns it if it exists.
Client (Browser) Web Server (Static)
| |
| 1. HTTP GET /image.png |
|--------------------------->|
| |
| 2. Lookup file on disk |
| or in memory cache |
| |
| 3. Serve file as response |
|<---------------------------|
| |
| Browser displays image |
Example request:
GET /images/logo.png HTTP/1.1
Host: example.com
Example output:
HTTP/1.1 200 OK
Content-Type: image/png
Cache-Control: public, max-age=31536000
(binary image data)
In this example, the server returns the image file and includes a caching header. The browser may store the image and avoid downloading it again on future visits.
Static content is fast because it requires very little server-side work. The server usually only needs to read a file and send it over the network. If the file is cached, the origin server may not be involved at all.
Static content is also very cache friendly. CDNs, browsers, and proxies can store static files close to users. This reduces latency and lowers the amount of traffic that reaches the origin server.
Static files are also easier to secure in some ways because they do not directly execute server-side code or connect to databases. A static image or stylesheet cannot run a database query by itself.
Example CDN-cached output:
HTTP/1.1 200 OK
Content-Type: text/css
Cache-Control: public, max-age=31536000
X-Cache: HIT
This response indicates that the file was served from cache. The origin server did not need to regenerate or reprocess the content.
Static content is limited when pages need real-time updates, personalization, or user-specific data. If every user should see a different dashboard, cart, account page, or recommendation list, static files alone are usually not enough.
Static content also requires a build or deployment process when the content changes. For example, a static documentation site may need to be rebuilt and redeployed whenever a page is updated.
Example limitation:
{
"page": "/dashboard.html",
"problem": "Static file cannot show user-specific account data without additional API calls or dynamic rendering."
}
Static content is excellent for stable assets, but it is not ideal for pages that must be customized for each request.
Nginx can serve static files directly from a directory. This is common for websites, documentation, frontend builds, and public assets.
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Example request:
GET /index.html HTTP/1.1
Host: example.com
Example output:
HTTP/1.1 200 OK
Content-Type: text/html
<html>
<body>
<h1>Welcome</h1>
</body>
</html>
If the requested file exists in /var/www/html, Nginx serves it directly. If the file does not exist, try_files returns a 404 Not Found.
Example missing-file output:
HTTP/1.1 404 Not Found
Content-Type: text/html
404 Not Found
This setup is simple, fast, and reliable for serving static websites or frontend assets.
Dynamic content is generated when the request is received. The server may run application code, check authentication, query a database, call another service, apply business rules, and then generate the final response.
Dynamic content is useful when responses need to change based on user identity, current data, permissions, form input, search terms, shopping cart contents, or real-time events.
Dynamic content can be generated on the server side or on the client side. In server-side rendering, the server builds the HTML before sending it. In client-side rendering, the server may send a static JavaScript application, and the browser fetches dynamic data from APIs.
Server-side dynamic content is generated by backend frameworks such as Express, Django, Flask, Ruby on Rails, Laravel, Spring Boot, ASP.NET, or PHP. The server receives the request and builds the response using runtime logic.
A typical request flow might look like this:
Client (Browser) Application Server
| |
| 1. HTTP GET /profile |
|-------------------------------------->|
| |
| 2. Run server-side code: |
| - Validate session |
| - Query database for user data |
| - Render template with user info |
| |
| 3. Return generated HTML |
|<--------------------------------------|
| |
| 4. Browser displays |
| personalized page |
| |
Example request:
GET /profile HTTP/1.1
Host: example.com
Cookie: session_id=abc123
Example output:
<html>
<body>
<h1>Welcome back, Alice</h1>
Your current plan is Premium.
</body>
</html>
The response is dynamic because the server used the session cookie to identify the user, retrieved account information, and generated personalized HTML.
Client-side dynamic content is common in single-page applications. The server first sends static HTML, CSS, and JavaScript files. After the page loads, JavaScript calls backend APIs to fetch or update data. The browser then changes the page without a full reload.
The process usually looks like this:
Example initial request:
GET /app HTTP/1.1
Host: example.com
Example initial output:
<div id="root"></div>
<script src="/static/app.js"></script>
Example API request from the browser:
GET /api/profile HTTP/1.1
Host: example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Example API output:
{
"name": "Alice",
"plan": "Premium",
"notifications": 3
}
The HTML and JavaScript files may be static, but the data loaded into the page is dynamic.
Dynamic content allows applications to personalize responses and reflect current data. This is essential for dashboards, user profiles, carts, search results, admin panels, social feeds, financial data, and many business workflows.
Dynamic systems can read from databases, apply permissions, calculate values, process forms, and return fresh results. They also support rich interactivity when combined with client-side JavaScript.
Example personalized response:
{
"user": "Alice",
"recommendedProducts": [
"Wireless Keyboard",
"USB-C Dock",
"Laptop Stand"
]
}
This response depends on the user and would likely be different for another visitor.
Dynamic content usually requires more server work. The application may need CPU time, memory, database queries, API calls, template rendering, and authentication checks. This can increase latency and reduce throughput compared with serving static files.
Caching is also harder because responses may vary by user, location, permission, or request parameters. A personalized dashboard should not be cached and served to the wrong user.
Dynamic systems also introduce more security risks. Bugs in server-side code can lead to problems such as SQL injection, cross-site scripting, broken access control, or data exposure.
Example dynamic error output:
{
"error": "Database query timed out",
"code": "DB_TIMEOUT"
}
This kind of error would not usually happen when serving a simple static file, but it can happen in dynamic systems that depend on databases or external services.
This example creates a dynamic route using Express. The route reads a name from the URL and generates a custom HTML response.
const express = require('express');
const app = express();
const PORT = 3000;
app.get('/hello/:name', (req, res) => {
const userName = req.params.name;
// Dynamic response
res.send(<h1>Hello, ${userName}!</h1>);
});
app.listen(PORT, () => {
console.log(Server running on http://localhost:${PORT});
});
Example request:
GET /hello/Alice HTTP/1.1
Host: localhost:3000
Example output:
<h1>Hello, Alice!</h1>
Example request:
GET /hello/Bob HTTP/1.1
Host: localhost:3000
Example output:
<h1>Hello, Bob!</h1>
The route is dynamic because the response changes based on the name parameter in the URL. Each request is processed at runtime.
Most real-world applications use a mix of static and dynamic content. Static assets such as images, fonts, CSS, and JavaScript bundles are often served through a CDN. Dynamic requests, such as login, checkout, dashboards, and API calls, are routed to application servers.
This hybrid approach gives teams the best of both worlds. Static assets can be served quickly and cheaply from cache, while dynamic endpoints handle user-specific logic and fresh data.
Example hybrid architecture:
Client
|
+--> CDN: images, CSS, JavaScript
|
+--> App Server: login, profile, checkout, API data
|
+--> Database: persistent user and business data
Example output:
{
"staticAssetsServedBy": "CDN",
"dynamicRequestsServedBy": "application server",
"databaseUsedFor": "user-specific data"
}
Some systems combine static and dynamic fragments in the same page. The mostly static parts of a page can be cached, while small personalized or frequently changing fragments are fetched separately.
For example, a product page may have static product images and descriptions, but dynamic inventory status, price, or personalized recommendations.
Example page composition:
Static shell:
- Header
- Product description
- Images
- Footer
Dynamic fragments:
- Current price
- Inventory status
- Recommended products
Example output:
{
"productId": "book-1",
"staticContent": "served from CDN",
"dynamicFragments": {
"price": 19.99,
"inventory": "in stock",
"recommendations": ["book-2", "book-3"]
}
}
This approach can improve performance while still supporting personalization and live data.
Dynamic content can sometimes be cached if it does not change frequently or if it is safe to reuse for multiple users. A generated blog page, product listing, or public news article may be dynamic at build time or first request, but cacheable afterward.
Client CDN/Reverse Proxy Application Server
| | |
| 1. Request /blog | |
|------------------------->| 2. Cache check |
| |-> if found, serve from cache |
| |-> else forward to origin |
|<-------------------------| |
| cached or newly fetched content |
Example first request output:
HTTP/1.1 200 OK
Content-Type: text/html
X-Cache: MISS
<html>
<body>
<h1>Latest Blog Post</h1>
</body>
</html>
Example later request output:
HTTP/1.1 200 OK
Content-Type: text/html
X-Cache: HIT
<html>
<body>
<h1>Latest Blog Post</h1>
</body>
</html>
The first request is generated by the application server and stored in cache. The next request can be served directly from the cache, reducing latency and server load.
Static and dynamic content have different performance profiles. Static content is usually faster and easier to scale because it requires little processing. Dynamic content is more flexible but often consumes more CPU, memory, database capacity, and network resources.
Performance planning should consider response time, throughput, scalability, bandwidth usage, caching, and failure behavior.
A simplified formula for concurrency can illustrate the difference in server load:
Max_Connections = Available_Threads_or_Workers / Average_Request_Time
For static files, Average_Request_Time is usually small because the server mainly reads and returns files. For dynamic requests, response time may increase because the server has to run application code, query databases, or call other services.
Example static calculation:
Available_Workers = 200
Average_Static_Request_Time = 0.01 seconds
Max_Connections ≈ 200 / 0.01
Max_Connections ≈ 20,000
Example dynamic calculation:
Available_Workers = 200
Average_Dynamic_Request_Time = 0.20 seconds
Max_Connections ≈ 200 / 0.20
Max_Connections ≈ 1,000
Example output:
{
"staticEstimatedCapacity": "20000 requests per second",
"dynamicEstimatedCapacity": "1000 requests per second",
"reason": "dynamic requests take longer to process"
}
This is only a simplified model, but it shows why static content can often support much higher traffic with the same infrastructure.
Static servers are easy to scale because static files can be copied to many locations and cached globally. CDNs are especially effective because they store files near users.
Dynamic servers are harder to scale because they often depend on application logic, shared databases, session storage, queues, caches, and external services. Scaling dynamic systems may require database read replicas, caching layers, load balancing, background jobs, or service partitioning.
Example scaling comparison:
{
"staticScaling": "copy files to CDN edge locations",
"dynamicScaling": "add app servers, scale database, manage cache and sessions"
}
Static scaling is usually simpler. Dynamic scaling requires more coordination because the system must keep data consistent and available.
Large static files such as images, videos, fonts, and JavaScript bundles can consume significant bandwidth. CDNs help by serving those files from edge locations instead of repeatedly sending them from the origin server.
Dynamic responses are often smaller, such as JSON or HTML fragments, but they may require heavier backend processing. For example, a dynamic product recommendation response may be only a few kilobytes, but generating it might require several database or machine learning service calls.
Example bandwidth output:
{
"staticVideoFile": "25 MB served from CDN",
"dynamicApiResponse": "4 KB served from app server",
"note": "small dynamic responses can still be expensive to compute"
}
Both bandwidth and compute cost matter. Static content is often bandwidth-heavy but cacheable. Dynamic content is often compute-heavy and harder to cache.
Different applications use different combinations of static and dynamic content. The right deployment model depends on whether the application needs personalization, frequent updates, database-backed behavior, or real-time interaction.
A fully static site is generated ahead of time and deployed to a CDN, object storage bucket, or static hosting platform. This works well for blogs, documentation, marketing pages, portfolios, landing pages, and product brochures.
Typical flow:
Client
|
| HTTP GET
v
[CDN Edge Server] -- retrieves from origin if needed --> [Origin Bucket or Host]
Example request:
GET /docs/getting-started.html HTTP/1.1
Host: docs.example.com
Example output:
<html>
<body>
<h1>Getting Started</h1>
This documentation page was generated ahead of time.
</body>
</html>
This design is fast, reliable, and inexpensive for content that does not need per-user customization.
A dynamic web app uses backend services to handle user-specific behavior. The server may manage sessions, authenticate users, process payments, query databases, and return HTML or JSON.
Static assets can still be offloaded to a CDN, while dynamic endpoints go to the application server.
Client
|
| GET /app
v
[Web/App Server] -- queries DB --> [Database]
|
| Serves HTML or JSON
v
Client updates the UI
Example request:
GET /api/cart HTTP/1.1
Host: shop.example.com
Cookie: session_id=abc123
Example output:
{
"items": [
{
"productId": "keyboard-1",
"quantity": 1,
"price": 49.99
}
],
"total": 49.99
}
This response is dynamic because it depends on the user’s current shopping cart. Another user would receive a different response.
Choose static content when the content seldom changes and does not need to be personalized for each user. Static content is ideal for marketing pages, documentation, blogs, product brochures, public assets, CSS, JavaScript bundles, images, and high-traffic pages that benefit from CDN caching.
Choose dynamic content when the response depends on active data, user identity, permissions, database queries, form submissions, real-time updates, or business logic. Dynamic content is better for dashboards, e-commerce carts, user profiles, admin panels, search results, recommendations, and transaction workflows.
Example decision guide:
{
"marketingPage": "static",
"documentation": "static",
"userDashboard": "dynamic",
"shoppingCart": "dynamic",
"productImage": "static",
"inventoryStatus": "dynamic"
}
Most real applications use both. Static resources like images, CSS, and JavaScript are cached aggressively, while dynamic endpoints handle user interactions and frequently changing data. This balance provides strong performance without giving up personalization or functionality.