Ditch all the other ideas and go for the cra-append-sw. It will save you a lot of time and pain.

It's as simple as installing the package, creating the service worker file in your main folder, and modifying your start and build commands in package.json file like this:

"start": "cra-append-sw --mode dev --env ./.env ./custom-sw.js && react-scripts start",
"build": "cra-append-sw --env ./.env ./custom-sw.js && react-scripts build",

And then you make sure to register the separate service worker in dev mode:

if ('serviceWorker' in navigator) {
  console.log('Trying to register custom sw');
    .then(function (registration) {
      console.log('Registration successful, scope is:', registration.scope);
    .catch(function (err) {
      console.log('Service worker registration failed, error:', err);

If like me you need access to environment variables in the service worker to initialize the firebase messaging module, this is the only simple option that doesn't require ejecting CRA.

I decided to post this answer because I myself overlooked the comments on the other answer and lost time unnecessarily looking for this solution.


If you would prefer disable the built in service-worker prior to your initial production deployment, then remove the call to serviceWorkerRegistration.register() from src/index.js and add your own service worker.

If your site/app has already been in production then swap it out for serviceWorkerRegistration.unregister(). After the user visits your page that has serviceWorkerRegistration.unregister(), the service worker will be uninstalled and it might take up to 24 hours for the cache to be invalidated (depending on how the service worker is served)

The other option would be to eject and configure their built in solution.

Related Query

More Query from same tag