# What Is WorkboxWebpackPlugin and How Does Offline Caching Work in Create React App?

> Learn how WorkboxWebpackPlugin enables offline caching in Create React App. Discover how to precache assets for faster load times and an enhanced user experience.

- Repository: [Meta/create-react-app](https://github.com/facebook/create-react-app)
- Tags: deep-dive
- Published: 2026-02-26

---

**WorkboxWebpackPlugin is a webpack integration that generates a service worker to precache build assets and enable offline functionality in Create React App production builds.**

Create React App (CRA) leverages the **WorkboxWebpackPlugin** to transform static builds into Progressive Web Apps capable of operating without network connectivity. In the `facebook/create-react-app` repository, this plugin is configured to inject a precache manifest directly into your service worker during production builds. Understanding how this integration works allows developers to customize caching strategies while maintaining automatic asset management.

## How WorkboxWebpackPlugin Integrates with CRA

The plugin is imported in the main webpack configuration file and conditionally applied only during production builds when a service worker source file exists.

```javascript
// packages/react-scripts/config/webpack.config.js
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');

```

### Production Build Configuration

When `isEnvProduction` is true and the service worker source file exists, CRA appends the **InjectManifest** instance to the webpack plugins array at lines 707-718.

```javascript
// packages/react-scripts/config/webpack.config.js (lines 707-718)
new WorkboxWebpackPlugin.InjectManifest({
  swSrc,                                   // Path to src/service-worker.js
  dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
  exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
  maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
}),

```

### Service Worker Source Resolution

The `swSrc` variable resolves to the developer-provided service worker entry point via the paths configuration in [`packages/react-scripts/config/paths.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/paths.js) at line 79.

```javascript
// packages/react-scripts/config/paths.js (line 79)
swSrc: resolveModule(resolveApp, 'src/service-worker'),

```

## The Offline Caching Mechanism

Workbox operates through two distinct phases: build-time manifest generation and runtime cache management.

### Precache Manifest Injection

The **InjectManifest** plugin scans all emitted webpack assets, generates a manifest of URLs with their content hashes, and replaces the `self.__WB_MANIFEST` placeholder in your source file. This list includes all static assets required for your application's shell, ensuring the app loads instantly on repeat visits.

### Runtime Caching Strategies

Beyond static precaching, the service worker intercepts fetch events to handle dynamic content. Developers can define custom strategies such as **StaleWhileRevalidate** for API calls or **CacheFirst** for images, which Workbox applies at runtime based on the routes you register.

### Build Output and Registration

After processing, the augmented service worker is emitted to [`build/service-worker.js`](https://github.com/facebook/create-react-app/blob/main/build/service-worker.js). When a user visits the deployed application, the browser registers this script, downloads the precached assets, and subsequent requests are served from the cache even when the device is offline.

## Implementing Offline Caching in Your Project

CRA provides a PWA template that demonstrates standard patterns, but you can extend these configurations to meet specific requirements.

### Default PWA Template Structure

When you initialize a project with the PWA template, [`src/service-worker.js`](https://github.com/facebook/create-react-app/blob/main/src/service-worker.js) contains the following standard implementation:

```javascript
// src/service-worker.js
/* eslint-disable no-restricted-globals */
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';

// Precache all assets generated by the build step.
precacheAndRoute(self.__WB_MANIFEST);

// Cache API calls with a stale-while-revalidate strategy.
registerRoute(
  ({ url }) => url.origin === self.location.origin && url.pathname.startsWith('/api/'),
  new StaleWhileRevalidate()
);

```

### Custom Runtime Caching Rules

Because CRA uses **InjectManifest**, you can add complex caching logic alongside the generated precache list without interfering with the build process:

```javascript
// src/service-worker.js (additional snippet)
import { CacheFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';

// Cache images with expiration
registerRoute(
  ({ request }) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images',
    plugins: [
      new ExpirationPlugin({
        maxEntries: 60,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
      }),
    ],
  })
);

```

### Disabling the Service Worker

To remove offline capabilities entirely, delete [`src/service-worker.js`](https://github.com/facebook/create-react-app/blob/main/src/service-worker.js) or ensure the file does not exist at the resolved path. When `swSrc` is missing, CRA skips the Workbox plugin entirely, producing a standard static build without service worker registration.

## Key Source Files in the CRA Repository

These files orchestrate the offline caching behavior:

| File | Purpose | Location |
|------|---------|----------|
| [`webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/webpack.config.js) | Configures `WorkboxWebpackPlugin.InjectManifest` for production | [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js) |
| [`paths.js`](https://github.com/facebook/create-react-app/blob/main/paths.js) | Resolves the absolute path to [`src/service-worker.js`](https://github.com/facebook/create-react-app/blob/main/src/service-worker.js) | [`packages/react-scripts/config/paths.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/paths.js) |
| [`noopServiceWorkerMiddleware.js`](https://github.com/facebook/create-react-app/blob/main/noopServiceWorkerMiddleware.js) | Provides a development-time no-op service worker to prevent caching issues | [`packages/react-dev-utils/noopServiceWorkerMiddleware.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-dev-utils/noopServiceWorkerMiddleware.js) |

## Summary

- **WorkboxWebpackPlugin.InjectManifest** is added to webpack only during production builds when [`src/service-worker.js`](https://github.com/facebook/create-react-app/blob/main/src/service-worker.js) exists, as configured in [`packages/react-scripts/config/webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js).
- The plugin replaces `self.__WB_MANIFEST` with a generated list of hashed asset URLs, enabling automatic precaching of your build output.
- **Offline caching** works by registering the generated service worker, which serves precached assets from the Cache Storage API and can apply custom runtime strategies for dynamic content.
- Developers maintain full control over caching behavior by editing [`src/service-worker.js`](https://github.com/facebook/create-react-app/blob/main/src/service-worker.js) while CRA handles the manifest generation and build integration.

## Frequently Asked Questions

### What is the difference between InjectManifest and GenerateSW in Workbox?

**InjectManifest** allows you to write your own service worker code while Workbox injects the precache manifest, whereas **GenerateSW** creates the entire service worker automatically without custom code. CRA uses **InjectManifest** to give developers control over runtime caching strategies and custom logic while still automating the precache list generation.

### How do I update the cached assets when deploying a new version?

Each production build generates new content hashes for changed assets. When the browser detects a different service worker byte-to-byte, it installs the new version and activates it after all tabs close, updating the precache manifest automatically through Workbox's built-in lifecycle management.

### Can I use WorkboxWebpackPlugin in development mode?

No, CRA intentionally excludes the plugin from development builds to prevent caching issues during active development. The [`noopServiceWorkerMiddleware.js`](https://github.com/facebook/create-react-app/blob/main/noopServiceWorkerMiddleware.js) utility serves a no-op service worker instead, ensuring development always reflects your latest code changes without stale cache interference.

### Why is my service worker not caching API responses?

By default, CRA's template only precaches static build assets defined in `self.__WB_MANIFEST`. You must explicitly add runtime caching routes using `registerRoute()` with appropriate strategies like **StaleWhileRevalidate** or **NetworkFirst** in your [`src/service-worker.js`](https://github.com/facebook/create-react-app/blob/main/src/service-worker.js) file to cache API calls or other dynamic resources.