How to Build PWAs in 2025 with React and JavaScript: A Complete Guide

In 2025, designing websites with a mobile-first approach has become more than just a trend—it’s essential. With over 58% of global web traffic coming from mobile devices, users now expect fast, reliable, and app-like experiences. This is where Progressive Web Apps (PWAs) really stand out.

PWAs bring together the best of both web and mobile apps—offering offline support, push notifications, and performance that’s almost indistinguishable from native apps—all while leveraging familiar tools like React and JavaScript.

This step-by-step guide will show you:

  • The key differences between PWAs and traditional web apps
  • How to create a PWA using React in 2025
  • Essential tools and best practices for building offline-first web apps

Whether you’re just starting out or you’re already comfortable with development, this tutorial will guide you through building fast, installable, and offline-capable PWAs with cutting-edge web technologies.

What Are Progressive Web Apps?

A Progressive Web App (PWA) is a type of web application that provides an app-like experience right in the browser. Unlike traditional websites, PWAs offer:

  • Offline functionality (thanks to service workers)
  • The ability to be installed on devices (via a web app manifest)
  • Instant loading (using smart caching techniques)
  • A responsive, mobile-friendly design

Key Components of a PWA:

  • Service Workers:
    • JavaScript files that run in the background
    • Cache assets and enable offline use
  • Web App Manifest:
    • A JSON file that defines app appearance (icons, theme colors, etc.)
    • Controls how the app looks when installed
  • HTTPS:
    • Essential for security
    • Enables service worker functionality

Some popular PWAs in action include Twitter Lite, Pinterest, and Spotify.

For a deeper dive, check out MDN’s PWA documentation.

Why Build PWAs in 2025?

PWAs offer fast performance, offline capabilities, and lower development costs with a single codebase. They deliver a seamless, app-like experience and improve SEO through mobile-first indexing, all without needing app store approval.

PWAs vs. Native Apps: Features Comparison

FeaturePWANative App
Development CostLower (single codebase)Higher (separate code for iOS & Android)
InstallationNo app store neededRequires app store approval
UpdatesInstant (auto-update)Requires manual updates via app store
Offline SupportYes (with service workers)Yes (depends on app design)
PerformanceFast, but slightly slower than nativeNear-native performance
DiscoverabilitySearchable on the webFound via app stores
Push NotificationsYesYes
Device AccessLimited (depends on browser support)Full access to device hardware

Key Benefits of PWAs in 2025

  • Better Performance:
    PWAs load 42% faster than traditional mobile websites, improving user experience.
  • Mobile-First Experience:
    Optimized for slow networks and low-end devices, ensuring smooth use across different platforms.
  • SEO-Friendly:
    PWAs are indexable by search engines, unlike native apps, helping with discoverability.
  • Lower Development Costs:
    One codebase for both desktop and mobile devices, cutting down on development time and costs.
  • Offline Access:
    Users can still interact with the app without an internet connection, increasing reliability.
  • App-Like Experience:
    Provides native-like experiences with features like push notifications and home screen installation.

Step-by-Step Guide to Building a PWA with React and JavaScript

Step 1: Set Up Your React Project

Start by creating a new React app with PWA support:

npx create-react-app my-pwa --template cra-template-pwa
cd my-pwa
npm start

This sets up a pre-configured PWA, complete with a service worker (service-worker.js).

Step 2: Configure the Web App Manifest

Customize your app’s appearance by editing public/manifest.json:

{
"name": "My PWA",
"short_name": "PWA",
"icons": [
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "/",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

Then, link it in public/index.html:

<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

Step 3: Implement a Service Worker

CRA automatically generates a service worker (src/service-worker.js). To customize caching, use Workbox:

// src/index.js
import * as serviceWorkerRegistration from './serviceWorkerRegistration';

// Register the service worker
serviceWorkerRegistration.register();

For offline caching, update service-worker.js:

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('my-pwa-cache').then((cache) => {
      return cache.addAll([
        '/',
        '/index.html',
        '/static/js/main.js',
        '/static/css/main.css',
      ]);
    })
  );
});

Step 4: Test and Optimize

Run a PWA audit with Google Lighthouse in Chrome DevTools (F12 > Lighthouse):

  1. Performance (aim for a 90+ score)
  2. PWA compliance (check installability and offline support)
  3. Accessibility & SEO

Pro Tip: Test on slow 3G networks to ensure your app performs well offline.

Tools and Libraries for PWAs in 2025

ToolPurpose
WorkboxSimplifies service worker caching
LighthouseAudits PWA performance
React PWA BoilerplatePre-configured starter kits
PWA BuilderGenerates installable packages

For more info, check out Google’s PWA resources.

Common PWA Challenges and Solutions

ChallengeSolution
Service worker not updatingUse versioning (const CACHE_NAME = 'v1')
App not installableVerify manifest.json and ensure HTTPS
Caching issuesClear storage in DevTools (Application > Clear storage)

Advanced PWA Features in 2025: Push Notifications, Background Sync, and More

Now that you’ve built the foundation of a Progressive Web App (PWA), let’s take it to the next level by adding advanced features that make it feel more like a native app.

In this section, we’ll explore:

  • Push Notifications – Keep users engaged, even when they’re not actively on your site.
  • Background Sync – Sync data with the server while offline.
  • Web Share & File System Access – Enable native-like sharing and file handling.
  • Advanced Caching Strategies – Use dynamic API caching for real-time applications.

Let’s dive in and level up your PWA!

1. Push Notifications in PWAs

Push notifications can increase user engagement by 50% or more when implemented correctly. Here’s how you can add them to your React PWA.

Step 1: Request Notification Permission

First, ask the user for permission to send notifications:

// src/components/NotificationButton.js
const requestNotificationPermission = async () => {
  if (!('Notification' in window)) {
    alert('This browser does not support notifications.');
    return;
  }

  const permission = await Notification.requestPermission();
  if (permission === 'granted') {
    console.log('Notification permission granted!');
    // Proceed with push subscription
  } else {
    console.warn('Notification permission denied.');
  }
};

return (
  <button onClick={requestNotificationPermission}>
    Enable Notifications
  </button>
);

Step 2: Subscribe to Push Notifications

Use the Push API to subscribe the user for push notifications:

// src/utils/pushService.js
const subscribeToPush = async () => {
  const swRegistration = await navigator.serviceWorker.ready;
  const subscription = await swRegistration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: 'YOUR_VAPID_PUBLIC_KEY', // From Firebase/backend
  });

  // Send subscription to your server
  await fetch('/api/save-subscription', {
    method: 'POST',
    body: JSON.stringify(subscription),
    headers: { 'Content-Type': 'application/json' },
  });
};

Step 3: Handle Push Events in the Service Worker

Set up push notifications in your service worker:

// public/service-worker.js
self.addEventListener('push', (event) => {
  const data = event.data.json();
  const options = {
    body: data.body,
    icon: '/icons/icon-192x192.png',
    badge: '/icons/badge.png',
  };

  event.waitUntil(
    self.registration.showNotification(data.title, options)
  );
});

Pro Tip: Use Firebase Cloud Messaging (FCM) for cross-browser push support.

2. Background Sync for Offline Data Sync

Background Sync allows your PWA to send data to the server, even when the user is offline.

Step 1: Register a Sync Event

// src/utils/syncService.js
const registerBackgroundSync = async () => {
  const swRegistration = await navigator.serviceWorker.ready;

  try {
    await swRegistration.sync.register('sync-posts');
    console.log('Background Sync registered!');
  } catch (err) {
    console.error('Background Sync failed:', err);
  }
};

Step 2: Handle Sync in the Service Worker

// public/service-worker.js
self.addEventListener('sync', (event) => {
  if (event.tag === 'sync-posts') {
    event.waitUntil(
      fetch('/api/sync-pending-posts', {
        method: 'POST',
        body: JSON.stringify({ posts: getPendingPosts() }),
      })
        .then(() => console.log('Synced successfully!'))
        .catch(() => console.log('Sync failed. Will retry later.'))
    );
  }
});

Use Case: This is perfect for syncing drafts, comments, or forms that need to be sent later.

3. Web Share & File System Access

A) Web Share API – Share Content Like a Native App

Share links, text, or files directly:

const shareData = {
  title: 'Check out this PWA!',
  text: 'I built an awesome PWA with React.',
  url: 'https://my-pwa.example.com',
};

if (navigator.share) {
  navigator.share(shareData)
    .then(() => console.log('Shared successfully'))
    .catch((err) => console.log('Error sharing:', err));
} else {
  alert('Web Share API not supported in this browser.');
}

B) File System Access API – Read/Write Files

Request file access to read or write files:

const fileHandle = await window.showOpenFilePicker();
const file = await fileHandle.getFile();
const contents = await file.text();
console.log('File content:', contents);

Note: The File System Access API is currently Chrome-only as of 2025.

4. Advanced Caching Strategies (Dynamic API Caching)

For real-time apps, implement strategies like Network-First, Cache-Fallback, or Stale-While-Revalidate.

Example: Stale-While-Revalidate

// public/service-worker.js
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.open('dynamic-cache').then((cache) => {
      return fetch(event.request)
        .then((response) => {
          cache.put(event.request, response.clone()); // Update cache
          return response;
        })
        .catch(() => cache.match(event.request)); // Fallback to cache
    })
  );
});

Best For:

  • News feeds
  • Stock market apps
  • Social media updates

5. Performance & Debugging Tips

IssueSolution
Push notifications not workingCheck VAPID keys & ensure HTTPS
Background Sync failingEnsure the sync event is registered
Cache not updatingUse cache.delete() in service worker

Debugging Tools:

  • Chrome DevTools > Application > Service Workers
  • Workbox Debug Mode (workbox.setConfig({ debug: true }))

7. Conclusion: Taking Your PWA to the Next Level

Building Progressive Web Apps in 2025 is easier than ever with React and JavaScript. By following this guide, you can create fast, offline-ready, and installable web apps that rival native experiences.

But why stop there? By integrating advanced features like push notifications, background sync, and advanced caching, your PWA can deliver performance and functionality that compete with even the best native apps.

Next Steps:

  • Deploy your PWA to Vercel or Netlify for easy hosting.
  • Integrate Firebase for cross-platform push notifications.
  • Test on lower-end devices to ensure smooth performance.
  • Explore WebAssembly (WASM) to achieve near-native speeds.

Leave a Comment