How to Create a PWA App with React: A Step-by-Step Guide

(Prefer videos? Watch a summary of this article below.)

Key Facts

  • A React progressive web app combines a standard React front end with a web app manifest and a service worker, so users can install it, cache it, and use it offline.
  • Vite is the fastest way to scaffold one today, mainly because the vite-plugin-pwa package generates the manifest and service worker for you, built on Workbox.
  • Chrome, Edge, and most Android browsers install PWAs directly from the browser bar. Safari on iOS needs a manual “Add to Home Screen” step.
  • HTTPS is non-negotiable. Service workers don’t register over plain HTTP, except for localhost.
  • A Lighthouse score above 90 for the PWA category is a reasonable target before you ship.

If you’ve ever wondered how to create a PWA app with React without rebuilding your whole stack, the honest answer is: you probably don’t have to. Most of the work is additive — a manifest file, a service worker, and a handful of configuration decisions layered on top of the React app you already know how to build. 

This guide walks you through that process end to end, from picking your tooling to deploying a production build that passes a Lighthouse audit.

What Is a React Progressive Web Application?

A React progressive web application is a React app enhanced with the browser APIs that make it installable, work offline, and behave like a native app on a phone or desktop. React handles the UI; the PWA layer — manifest plus service worker — handles everything that happens once the network drops or the user taps “Install.”

Core characteristics of progressive web applications

Four traits define a PWA, and a React app has to earn all of them to count:

  • It needs to be reliable, loading instantly even on flaky connections thanks to cached assets. 
  • It needs to be fast, since React’s rendering already helps, but caching removes network latency entirely. 
  • It needs to be installable, with a manifest that lets the browser add an icon to the home screen. 
  • It should also be responsive, adapting cleanly from a phone screen to a desktop window rather than assuming one layout. 

Many production PWAs go further, adding push notifications and background synchronization so the app can re-engage users or sync data once connectivity returns — both of which sit on top of the same service worker that handles caching.

How progressive web applications differ from native and traditional web applications

The table below lays out where a PWA sits between a standard website and a native mobile app.

AspectTraditional web appPWANative app
InstallationNone — always a URLOne-tap, no app storeApp store download
Offline accessUsually noneYes, via cached assetsYes, built-in
Update processInstant on reloadInstant, service worker refreshes cacheWaits on app store review
DistributionJust share a linkShare a link or install promptApp store listing required
Device API accessLimitedGrowing (camera, notifications, geolocation)Full access
Typical build costLowestLow to moderateHighest (often two codebases)

A PWA won’t fully replace a native app that needs deep hardware access, but for content, commerce, and internal tools, it closes most of the gap at a fraction of the cost.

What Do You Need Before Building a React Progressive Web Application?

You need a standard React toolchain, a build tool that can generate a service worker, and a hosting setup that serves everything over HTTPS. Nothing exotic — most teams already have two of the three in place.

Required tools and technologies

ToolRole
Node.js (18+)Runs the build tooling and dev server
ViteBundles the app and dev-serves it with fast Hot Module Replacement (HMR)
vite-plugin-pwaGenerates the manifest and service worker automatically
WorkboxPowers the caching strategies under the hood
React 18+Renders the UI
A code editor with ESLintCatches config and syntax errors early
HTTPS-capable hostingRequired for service worker registration in production

Browser and hosting requirements

Service workers register only on secure origins — HTTPS in production or localhost during development, with no exceptions. Every modern browser supports the core PWA APIs. However, Safari lags on background sync and push notifications, so test on an actual iPhone before you promise those features to iOS users. 

On the hosting side, you need a host that lets you set custom headers and serves a fallback index.html for client-side routes; static hosts like Netlify, Vercel, or Cloudflare Pages handle both out of the box.

Choosing between Vite and a React framework

FactorVite + ReactNext.js / Remix
Setup speedMinutes, minimal configSlightly more scaffolding
PWA plugin supportMature (vite-plugin-pwa)Requires extra config or a separate package
Server-side rendering (SSR)No, by defaultYes, built-in
Best fitSPA-style (Single-Page Application) dashboards, tools, client appsContent sites needing SEO and SSR

If your app doesn’t need server rendering, Vite is the more direct path to a React PWA. Frameworks with SSR can still ship a PWA, but the service worker setup takes more care around hydration.

How Do You Set Up a React Project with Vite?

You scaffold a project with Vite’s CLI, then layer the PWA plugin on top. This is the fastest route if you’re figuring out how to make a React app PWA-ready without inheriting a legacy build.

Creating a new Vite project

Run npm create vite@latest my-pwa-app — –template react-ts (drop -ts if you’re not using TypeScript), then cd my-pwa-app && npm install. This gives you a minimal React app with Vite’s dev server, which is already faster than most Webpack setups you may have used before.

Installing vite-plugin-pwa and Workbox

Add the plugin with npm install -D vite-plugin-pwa. You don’t need to install Workbox separately — vite-plugin-pwa bundles it and generates the service worker for you at build time, using whichever caching strategy you configure.

Configuring the project structure

Import and register the plugin in vite.config.ts, keep your manifest icons in public/icons/, and add an offline.html fallback if you want a custom message when a user is disconnected and hits an uncached route. Nothing about your component structure needs to change — the PWA config lives alongside your existing Vite setup, not inside it.

React PWA Architecture

How Do You Configure the Web App Manifest?

The manifest is a JSON file that tells the browser your app’s name, icons, colors, and how it should launch once installed. With vite-plugin-pwa, you define it as an object inside vite.config.ts, and the plugin writes it to manifest.webmanifest during the build.

Manifest fieldPurposeExample
nameFull app name shown on install prompts“My Task Manager”
short_nameName under the home screen icon“Tasks”
start_urlPage loaded when the app opens“/”
displayChrome/UI shown when installed“standalone”
theme_colorBrowser toolbar color“#1a1a2e”
background_colorSplash screen background“#ffffff”
iconsArray of icon sizes and paths192×192, 512×512 PNGs

Adding names, colors, and display settings

Set display: “standalone” if you want the app to open without browser chrome, which is what makes it feel native. theme_color and background_color control the splash screen users see for a split second on launch — worth matching to your brand rather than leaving as Vite’s defaults.

Preparing application icons and screenshots

You need at minimum a 192×192 and a 512×512 icon in PNG format; maskable icons (with safe padding for Android’s circular crop) are worth generating too, since Android will otherwise crop your icon awkwardly. Tools like PWA Asset Generator can produce the full icon and screenshot set from a single source image in one command.

Defining start URL and scope

start_url sets where the app opens from the home screen icon, and scope limits which routes count as “inside” the installed app versus a link that should open in the regular browser. For most single-page apps, scope: “/” is correct — narrow it only if part of your site should stay outside the installed experience.

How Do You Add a Service Worker and Offline Support?

The service worker is a background script that intercepts network requests and decides whether to serve them from cache or the network. It’s what makes offline mode possible, and vite-plugin-pwa generates most of it for you based on the strategy you pick.

Registering the service worker

With the plugin configured for registerType: “autoUpdate”, registration happens automatically on build — you don’t write navigator.serviceWorker.register() by hand. Import the auto-generated virtual:pwa-register module in your entry file if you want control over the update prompt shown to users.

Choosing a Workbox caching strategy

Workbox ships a handful of strategies, and picking the right one per resource type matters more than picking one for everything. 

  • Cache-first suits static assets like fonts and images that rarely change. 
  • Network-first suits API calls where fresh data matters but a cached fallback is acceptable. 
  • Stale-while-revalidate splits the difference, serving cache instantly while quietly fetching an update in the background.

Caching static assets and API responses

vite-plugin-pwa precaches your build output (JS, CSS, and the app shell) automatically. For API responses, add a runtimeCaching rule in the config targeting your API’s URL pattern with a network-first strategy and a short expiration window, so users see live data when online and a recent snapshot when they’re not.

Creating an offline fallback page

Precache a lightweight offline.html and configure Workbox’s navigateFallback to serve it when a navigation request fails and nothing matching is in the cache. A plain page with your logo and a “you’re offline” message beats a browser’s default error screen by a wide margin.

Handling service worker updates

Every deploy generates a new service worker, but browsers don’t activate it immediately — they wait for open tabs to close, unless you call skipWaiting(). Pair that with a small “New version available, refresh?” toast so users control when the update lands, rather than the page silently changing under them.

SaM Solutions’ talented React team is available to support you in any aspect of your React-based web or mobile development project.

How Do You Make the React Application Installable?

A browser offers to install your app only when it meets a specific checklist. Miss one item and the install prompt simply never fires, with no error to tell you why.

Meeting browser installability requirements

Chrome requires HTTPS, a valid manifest with a name, icons, and start_url, plus a registered service worker with at least a fetch handler. Miss any of these, and beforeinstallprompt never fires — DevTools’ Application tab will tell you exactly which requirement failed.

Creating a custom installation prompt

Browsers hide the native install banner behind an event you can capture: listen for beforeinstallprompt, call event.preventDefault(), stash the event, and trigger event.prompt() from your own “Install App” button. This gives you control over timing instead of an install nag appearing mid-task.

Supporting installation on mobile and desktop devices

Android and desktop Chrome both support the beforeinstallprompt flow above. iOS Safari doesn’t fire that event at all — Apple only supports manual installation through the Share menu’s “Add to Home Screen” option, so if a meaningful share of your users are on iPhones, add an on-screen hint showing them that path.

How Do You Test and Debug a React Progressive Web Application?

You test a PWA in layers: an automated audit for checklist items, manual offline testing for caching logic, and cross-browser passes for parts that don’t behave consistently everywhere.

Running a Lighthouse audit

Open Chrome DevTools, go to the Lighthouse tab, and run a PWA audit against your production build — not the dev server, since Vite’s dev mode doesn’t register the real service worker. Lighthouse flags missing manifest fields, unmet installability criteria, and performance issues in one pass, which makes it the fastest first check after any config change.

Testing offline behavior in Chrome DevTools

Under the Application tab, set Service Workers to “Offline” and reload the page. If your caching config is right, the app shell should load instantly with no network requests firing; if it doesn’t, the Network tab will show exactly which request is failing and why it wasn’t served from the cache.

Checking the manifest and service worker

The Application tab’s Manifest panel flags any missing or malformed field before Lighthouse even runs, and the Service Workers panel shows registration status, current cache contents, and lets you force an update without redeploying — handy for debugging update logic in isolation.

Testing across browsers and devices

Run the install flow on real Android and iOS devices, not just simulators — install prompts and home screen behavior differ enough between them that emulators miss real bugs. BrowserStack or a spare phone drawer both work; the point is confirming the experience on the browsers your actual users have.

How Do You Deploy and Optimize a React Progressive Web Application?

Deployment is mostly standard React deployment, with two additions that matter specifically for a PWA: HTTPS is mandatory, not optional, and your server needs to handle client-side routing correctly so cached routes don’t 404 on refresh.

Building the production version

Run npm run build. Vite outputs a dist/ folder containing your bundled app plus the generated manifest.webmanifest and service worker file — everything the PWA needs, ready to deploy as static files.

Deploying over HTTPS

Any modern static host — Vercel, Netlify, Cloudflare Pages, or your own server behind a reverse proxy with a Let’s Encrypt certificate — gets you HTTPS by default. Skip this, and the service worker won’t register, silently disabling every offline feature you built.

Configuring server headers and SPA routing

Set your host to redirect unmatched routes to index.html, so React Router can handle them client-side, and add a short cache-control header for index.html itself so users pick up new deploys promptly rather than serving a stale shell for days.

Improving performance and Core Web Vitals

Code-split routes with React.lazy, compress images, and let Workbox’s precaching do the heavy lifting on repeat visits — a well-configured PWA often beats a plain SPA on Largest Contentful Paint simply because the second visit loads from cache instead of the network. Run Lighthouse after each meaningful change to catch regressions before they ship.

Applying security and accessibility best practices

Set a Content-Security-Policy header, keep dependencies patched, and use vite-plugin-pwa’s injectManifest mode only if you need custom service worker logic beyond what Workbox’s generated config offers. On accessibility, don’t let the install button or offline banner trap keyboard focus — test both with a screen reader before calling the feature done.

Why Choose SaM Solutions for React App Development?

Building a React PWA well means getting the manifest, service worker, and deployment pipeline right on the first pass, not iterating in production while users hit broken caches.

SaM Solutions’ React.js development team has spent years shipping React apps across ecommerce, healthcare, and logistics, and our front-end development services cover exactly this kind of work — from initial architecture decisions like Vite versus a full framework, through manifest and caching strategy, to a Lighthouse-audited production deploy. 

Whether you need a small team to build a React PWA from scratch or an experienced developer to review and harden one you’ve already started, we can staff the project to match.

Conclusion

Learning how to create a PWA app with React isn’t a rewrite — it’s an additive process: a manifest, a service worker, and a set of caching decisions layered onto a React app you likely already know how to build. 

Vite and vite-plugin-pwa handle most of the generated code, which leaves you to make the decisions that actually matter — caching strategy, icon set, offline fallback — and to verify the result with a Lighthouse audit before it ships. 

Follow the steps above in order, and you’ll have an installable, offline-capable React app running on real HTTPS infrastructure well within an afternoon.

FAQ

How much does it cost to develop a React progressive web application?

Costs vary with scope, but a straightforward React PWA built on an existing design typically runs from a few thousand dollars for a small internal tool to well into five figures for a full-featured customer-facing app with offline sync, notifications, and multi-team QA.

How long does it take to build a React progressive web application?

How can a React progressive web application be monetized?

Does a React progressive web application need a backend?

Editorial Guidelines

Contact us

Prefer a more personal approach? Email us — we’ll get back to you shortly. Share your ideas or requirements, and we’ll help you refine them.

What happens next?
1

Shortly after receiving your request, one of our experts will contact you to discuss and clarify your business needs.

2

If needed, we’ll sign an NDA to ensure maximum confidentiality.

3

Your dedicated Account Manager will prepare a detailed project proposal, which may cover cost estimates, timelines, team CVs, and other relevant details.

4

Once approved, your project team can begin work within ten business days.