Skip to main content

Database and Caching Overview

Database and caching in frontend system design means storing, reusing, and organizing data across different layers of the application.

Frontend applications use caching and client-side storage to reduce latency, improve responsiveness, decrease server load, and support a more reliable user experience.

Database & Caching = Store useful data closer to the user and reuse it safely

One-line idea: Database & Caching Overview = Use layered caching and browser storage to make frontend apps faster, more reliable, and more scalable while managing stale data carefully.

Core Concepts​

Why It Matters​

Modern frontend apps do not fetch everything from the server every time.

They use multiple caching and storage layers to make the app feel faster and more stable.

Caching helps with:

  • faster page loads
  • fewer network requests
  • reduced backend load
  • better scalability
  • better performance during unstable networks
  • smoother user experience

The main challenge is not only storing data.

The harder part is keeping cached data correct and up to date.

Caching Strategy Overview​

Caching should be treated as a hierarchy, not as one single mechanism.

The same data may exist in multiple places:

  • browser HTTP cache
  • service worker cache
  • API cache
  • application state store
  • persistent browser storage
Caching Strategy = Know which layer owns which data

If ownership is unclear, the app can show stale, duplicated, or inconsistent data.

Main Caching Layers​

LayerMain Purpose
HTTP CacheCache static assets before app code runs
Service Worker CacheProgrammatically control cache and offline behavior
API Response CacheStore previously fetched server responses
State Management CacheKeep shared data in memory for fast UI access
Browser StoragePersist data locally in the browser
Normalized StoreOrganize entities to avoid duplication

HTTP Caching​

HTTP caching is the browser's first optimization layer.

It works before application JavaScript executes.

It is commonly used for static assets like:

  • JavaScript bundles
  • CSS files
  • fonts
  • images

The browser can reuse these files across multiple visits instead of downloading them every time.

HTTP Cache = Browser reuses already downloaded resources

HTTP Caching: Important Headers​

HTTP caching is controlled using headers such as:

HeaderPurpose
Cache-ControlDefines how and how long a resource can be cached
ETagHelps validate whether the cached resource changed
ExpiresDefines when a cached resource becomes stale

In production, static assets are often versioned using content hashes.

app.abc123.js
style.def456.css

This allows aggressive caching while still making sure users get updated files after deployment.

Service Worker Caching​

Service workers provide a programmable caching layer between the browser and the network.

Unlike HTTP caching, developers can directly control how requests are handled.

Service workers can use strategies like:

  • Cache First
  • Network First
  • Stale While Revalidate
Service Worker Cache = Developer-controlled cache between app and network

This is useful for balancing freshness, speed, and offline support.

Service Worker Caching: Offline Support​

Offline support is one of the most valuable service worker use cases.

When the network is unavailable, the app can still serve cached resources.

This helps create:

  • offline-first experiences
  • Progressive Web App behavior
  • faster repeat visits
  • better resilience during network failure

Large-scale applications use service workers to reduce perceived latency and improve reliability.

API Response Caching​

API response caching stores previously fetched backend responses inside the application layer.

This avoids requesting the same data again and again.

Common tools include:

  • React Query
  • SWR
  • RTK Query

These tools help with:

  • automatic caching
  • background revalidation
  • stale data handling
  • cache invalidation
API Cache = Store fetched API data and reuse it across the app

API Response Caching: Main Challenge​

The hard part of API caching is not saving the response.

The hard part is deciding when the cached data should be considered outdated.

A good API cache should define:

  • who owns the data
  • when data expires
  • when data should refresh
  • what action invalidates the cache

Without clear rules, the UI may show stale or inconsistent information.

State Management as Cache​

State management often works like an in-memory cache.

Data fetched from APIs can be stored and shared across components.

This avoids repeated backend calls and improves UI responsiveness.

Examples of state/cache layers:

  • Redux store
  • Zustand store
  • Context state
  • React Query cache
  • RTK Query cache
State Store = Fast in-memory access for UI data

State Management as Cache: Scaling Problem​

As apps grow, state management becomes less about simply sharing data.

It becomes about synchronizing:

  • UI state
  • cached API responses
  • backend data
  • persistent browser storage

Poorly designed state stores can create:

  • stale data
  • duplicated data
  • hard debugging
  • inconsistent UI

Practical Examples​

Data Normalization​

Normalization means organizing data into predictable structures to reduce duplication.

Instead of storing deeply nested objects everywhere, entities are stored separately and linked using IDs.

Normalization = Store entities once and reference them by ID

Example idea:

users by ID
posts by ID
comments by ID

This makes updates easier because one entity can be updated in one place.

Data Normalization: Why Normalization Helps​

Normalization improves large frontend apps by reducing duplicated state.

It helps with:

  • efficient updates
  • easier cache management
  • lower memory usage
  • predictable data structure
  • fewer inconsistent copies

Enterprise state systems and GraphQL caching solutions often rely on normalized data models.

Browser Storage Mechanisms​

Frontend apps can also persist data inside the browser.

Common browser storage options:

StorageMain Use
Local StoragePersistent key-value data
Session StorageTemporary tab-level data
CookiesSmall request-attached data
IndexedDBLarge structured browser database

Each storage option has different behavior, limits, and security considerations.

Local Storage​

Local Storage provides persistent key-value storage.

Data remains available even after the browser is closed and reopened.

Good use cases:

  • user preferences
  • application settings
  • feature flags
  • lightweight cached data
Local Storage = Persistent browser key-value storage

Do not store sensitive data in Local Storage because it is accessible through JavaScript.

If the app has an XSS vulnerability, the data can be exposed.

Session Storage​

Session Storage is similar to Local Storage but scoped to a single browser tab.

It is cleared when the tab or session ends.

Good use cases:

  • temporary workflow data
  • multi-step form data
  • session-specific UI state
Session Storage = Temporary storage for one tab session

Use it when data should not persist forever.

Cookies​

Cookies store small amounts of data that can be automatically sent with HTTP requests.

They are commonly used for authentication-related flows when configured securely.

Important cookie attributes:

  • HttpOnly
  • Secure
  • SameSite
Cookies = Small storage that can travel with HTTP requests

Cookies should be used carefully because they are sent with requests.

Too many or too large cookies can negatively affect network performance.

IndexedDB​

IndexedDB is a browser-native database for storing large amounts of structured data.

Compared to Local Storage, IndexedDB supports:

  • larger storage capacity
  • indexes
  • transactions
  • complex queries
  • structured data
IndexedDB = Browser database for large and structured client-side data

Apps like Figma, Notion, and Google Docs use IndexedDB-style storage patterns to support offline functionality, synchronization, and local persistence.

Use IndexedDB when app requirements start looking like a real client-side database.

Architectural Considerations​

Caching improves performance, but it also increases system complexity.

Before adding caching layers, engineers should define:

  • cache ownership
  • expiration policy
  • invalidation rules
  • synchronization mechanism
  • security boundaries
  • consistency expectations
Caching is easy to add.
Correct caching is hard to maintain.

Security Considerations​

Client-side storage needs careful security decisions.

Important rules:

  • avoid storing sensitive data in Local Storage
  • use secure cookies for authentication when needed
  • use HttpOnly, Secure, and SameSite cookie attributes
  • consider encryption for sensitive local data
  • choose storage based on risk and access requirements
  • remember that JavaScript-accessible storage can be exposed by XSS

The more data stored on the client, the more carefully security must be handled.

Database and Caching Table​

AreaMain Idea
HTTP CacheBrowser caches static resources
Service Worker CacheDeveloper controls request and cache behavior
API CachePreviously fetched responses are reused
State ManagementIn-memory cache for UI data
NormalizationStore entities once and reference by ID
Local StoragePersistent key-value data
Session StorageTemporary tab-scoped data
CookiesSmall data sent with HTTP requests
IndexedDBLarge structured browser database

Summary​

Database & Caching Overview = Use layered caching and browser storage to make frontend apps faster, more reliable, and more scalable while managing stale data carefully.

HTTP Cache -> static assets
Service Worker -> offline and custom cache logic
API Cache -> fetched server data
State Store -> fast in-memory UI data
Browser Storage -> persistent local data
Normalization -> fewer duplicates and easier updates

Fast data is useful only when it is also correct.