DEV Community

Odiri Teddie
Odiri Teddie

Posted on

Service Workers Explained Like You're Building Your First PWA


Spend any real time poking around Progressive Web Apps (PWAs), and sooner or later you’ll run headfirst into Service Workers.

The line you’ll hear over and over is that they’re "a proxy between your app and the network."

Which is true, and also close to useless if what you’re actually after is why they exist and what they buy you.

Here’s the framing that finally made it stick for me:

A Service Worker is a programmable layer sitting between your app and the internet, handing you the controls over how every request gets dealt with.

That’s the thing that unlocks offline support, smarter caching, background sync, push notifications — the stuff that starts closing the gap between a web app and a native one.

So in this piece I want to build up a mental model of Service Workers, show where they sit inside a PWA, and make the case for why they’re worth your attention even if you never plan to go fully offline.


What Problem Do Service Workers Solve?

Say you’ve thrown together a little weather app.

Each time someone opens it, the browser pulls down:

  • HTML
  • CSS
  • JavaScript
  • Images
  • Fonts
  • API responses

Now knock out their connection, and the whole thing just falls over.

Not because the browser can’t paint the UI — it’s because it has no idea what it’s meant to do the moment a request comes back empty.

With no Service Worker in the picture, every request walks the same simple line:

Browser
     ↓
 Internet
     ↓
 Server
     ↓
 Browser
Enter fullscreen mode Exit fullscreen mode

And the browser gets almost no say in any of it.

A Service Worker changes the flow.

Browser
     ↓
Service Worker
     ↓
Cache or Network
     ↓
Browser
Enter fullscreen mode Exit fullscreen mode

Now your application can decide:

  • Should this request come from the cache?
  • Should it go to the network?
  • If they’re offline, do I fall back to something cached?
  • Is this response worth holding onto for next time?

The browser’s defaults stop being the only option, and the decisions become yours.


What Exactly Is a Service Worker?

At its core, a Service Worker is just a JavaScript file — but one that runs off to the side of your actual page.

It never touches the DOM, which already sets it apart from your React or Vue code.

Picture it more as a background process, sitting quietly and listening for browser events and network traffic.

Its responsibilities often include:

  • Caching application assets
  • Intercepting network requests
  • Serving cached responses
  • Managing offline experiences
  • Receiving push notifications
  • Performing background synchronization

And because it lives apart from your UI, it can keep doing some of its work even when nobody has your app open.


The Service Worker Lifecycle

Once the lifecycle clicks, a lot of the "why does it behave like that?" weirdness around Service Workers goes away.

It moves through three stages.

1. Registration

This is your app letting the browser know a Service Worker is around.

if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("/service-worker.js");
}
Enter fullscreen mode Exit fullscreen mode

Nothing special happens yet.

The browser simply knows about the worker.


2. Installation

Now the worker downloads itself and installs.

This is typically the moment you cache your static assets.

self.addEventListener("install", (event) => {
  console.log("Installing...");
});
Enter fullscreen mode Exit fullscreen mode

Think of it as the app packing a bag for later.


3. Activation

With install done, the worker flips over to active.

self.addEventListener("activate", (event) => {
  console.log("Activated");
});
Enter fullscreen mode Exit fullscreen mode

This is your chance to clear out stale caches from previous versions.

And from the moment it’s active, it starts catching requests.


Intercepting Network Requests

This is the part where Service Workers actually earn their reputation.

Every single network request can be caught mid-flight.

self.addEventListener("fetch", (event) => {
  console.log(event.request.url);
});
Enter fullscreen mode Exit fullscreen mode

Rather than letting the browser fetch things the usual way, you get to make the call on each request yourself.

That freedom is exactly what the more advanced caching strategies are built on.


Caching Isn't Just About Speed

Many developers associate caching with performance.

That’s true, but it’s only half of it.

Caching also improves:

  • Reliability
  • Offline support
  • Reduced bandwidth usage
  • Faster repeat visits
  • Better user experience on slow networks

Imagine a news application.

The newest stories might still need a connection, but the ones a reader already opened can sit there ready offline.

Which beats staring at the browser’s dinosaur error page by a wide margin.


Common Caching Strategies

Different resources benefit from different approaches.

Cache First

Check the cache before the network.

Cache
   ↓
Network (if needed)
Enter fullscreen mode Exit fullscreen mode

Best for:

  • Images
  • Fonts
  • CSS
  • JavaScript bundles

Network First

Try the network first.

Network
    ↓
Cache (fallback)
Enter fullscreen mode Exit fullscreen mode

Useful for:

  • API requests
  • Dashboards
  • Live content

Stale While Revalidate

Immediately serve cached content while downloading a fresh version in the background.

Cache
 ↓
User sees content immediately

Network
 ↓
Cache updated
Enter fullscreen mode Exit fullscreen mode

This strategy creates applications that feel extremely responsive.

It's widely used because it balances speed with freshness.


How PWAs Use Service Workers

A Progressive Web App isn't defined by one feature.

Instead, several technologies work together.

Manifest
        +
Service Worker
        +
HTTPS
        +
Responsive Design
        =
Progressive Web App
Enter fullscreen mode Exit fullscreen mode

The manifest controls installation.

Responsive design keeps it usable from a phone to a widescreen monitor.

HTTPS provides security.

And the Service Worker is what brings the offline behaviour, the caching, and the background tricks to the table.

Pull the Service Worker out and most of what makes a PWA feel like a PWA goes with it.


Things Service Workers Can't Do

For all they can do, Service Workers aren’t a magic wand.

They cannot:

  • Access the DOM directly
  • Modify React components
  • Read page variables automatically
  • Run on insecure HTTP connections (except localhost)
  • Replace your backend

They sit alongside your app and support it; they were never meant to stand in for its architecture.


Common Mistakes

Almost everyone trips over the same few things the first time they play with Service Workers.

Caching Everything

Not every response belongs in the cache.

Dynamic data often needs different strategies than static assets.


Forgetting Cache Cleanup

Old cache versions accumulate over time.

Always remove outdated caches during activation.


Assuming Everything Works Offline

Offline support requires planning.

It’s on you to draw the line between what’s safe to cache and what genuinely needs a live connection.


Ignoring Updates

Shipping a new deploy doesn’t just swap out the Service Worker that’s already running.

If you don’t get your head around the update lifecycle, you’ll end up with users quietly stuck on an old build.


Should Every Website Use a Service Worker?

Not necessarily.

A simple marketing website may not benefit much.

The apps that tend to get the most out of them include:

  • SaaS dashboards
  • E-commerce platforms
  • Productivity tools
  • Travel applications
  • Educational platforms
  • News applications
  • Field service applications
  • Offline-first business tools

The more your users are counting on the thing being fast and dependable, the more a Service Worker pays for itself.


Final Thoughts

Service Workers feel daunting early on, mostly because they drop you into a new execution context and ask you to rethink how requests work.

But the moment the underlying model lands, the rest tends to fall into place quickly.

Stop picturing each request as something the browser just fires off to a server on autopilot. Picture a gatekeeper instead — every request stops at it first, and that’s where your app gets to choose: go fetch something fresh, hand back a cached copy, or handle a flaky connection without falling apart.

That one shift in how you see requests is really what the whole idea of a PWA rests on.

Small weekend project or a full production app, it doesn’t much matter — getting comfortable with Service Workers is one of those steps that quietly makes everything you ship faster, sturdier, and nicer to actually use.

Top comments (0)