Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to add service workers in React

Service workers enable powerful features like offline support, background sync, and push notifications in React applications. As the creator of CoreUI with 12 years of React development experience, I’ve implemented service workers in countless production applications.

The most reliable approach is to use Create React App’s built-in service worker support with the Workbox library.

Install Dependencies

React applications created with Create React App come with service worker support. For existing apps, install Workbox:

npm install workbox-webpack-plugin workbox-precaching

Register the Service Worker

In your src/index.js, register the service worker:

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import * as serviceWorkerRegistration from './serviceWorkerRegistration'

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App />)

serviceWorkerRegistration.register()

Create Service Worker Registration

Create src/serviceWorkerRegistration.js:

const isLocalhost = Boolean(
  window.location.hostname === 'localhost' ||
  window.location.hostname === '[::1]' ||
  window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
)

export function register(config) {
  if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`

      if (isLocalhost) {
        checkValidServiceWorker(swUrl, config)
      } else {
        registerValidSW(swUrl, config)
      }
    })
  }
}

function registerValidSW(swUrl, config) {
  navigator.serviceWorker
    .register(swUrl)
    .then(registration => {
      registration.onupdatefound = () => {
        const installingWorker = registration.installing
        if (installingWorker == null) {
          return
        }
        installingWorker.onstatechange = () => {
          if (installingWorker.state === 'installed') {
            if (navigator.serviceWorker.controller) {
              console.log('New content available, please refresh')
              if (config && config.onUpdate) {
                config.onUpdate(registration)
              }
            } else {
              console.log('Content cached for offline use')
              if (config && config.onSuccess) {
                config.onSuccess(registration)
              }
            }
          }
        }
      }
    })
    .catch(error => {
      console.error('Service worker registration failed:', error)
    })
}

function checkValidServiceWorker(swUrl, config) {
  fetch(swUrl, { headers: { 'Service-Worker': 'script' } })
    .then(response => {
      const contentType = response.headers.get('content-type')
      if (
        response.status === 404 ||
        (contentType != null && contentType.indexOf('javascript') === -1)
      ) {
        navigator.serviceWorker.ready.then(registration => {
          registration.unregister().then(() => {
            window.location.reload()
          })
        })
      } else {
        registerValidSW(swUrl, config)
      }
    })
    .catch(() => {
      console.log('No internet connection, running in offline mode')
    })
}

export function unregister() {
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.ready
      .then(registration => {
        registration.unregister()
      })
      .catch(error => {
        console.error(error.message)
      })
  }
}

Create the Service Worker

Create public/service-worker.js:

import { precacheAndRoute } from 'workbox-precaching'

precacheAndRoute(self.__WB_MANIFEST)

self.addEventListener('install', event => {
  console.log('Service worker installed')
})

self.addEventListener('activate', event => {
  console.log('Service worker activated')
})

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      return response || fetch(event.request)
    })
  )
})

Test Offline Support

Build your app and test with a local server:

npm run build
npx serve -s build

Open DevTools → Application → Service Workers to verify registration. Toggle offline mode to test caching.

Best Practice Note

This is the same approach we use in CoreUI’s Progressive Web App templates to provide reliable offline support and improved performance. Service workers are essential for modern React applications that need to work offline or in poor network conditions.

For production apps, consider using CoreUI’s React Admin Template which includes pre-configured PWA support with service workers, offline caching, and push notifications out of the box.

If you’re working with React state management, you might also want to learn how to use Context API in React to share service worker state across your application.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author