# Migrate from a native app to a PWA

> What a PWA is and the two pieces it rests on, a manifest supplying install metadata and a service worker that can serve offline, with minimal examples.

At the end of this guide you have a scoped inventory of the native app's features mapped to
web equivalents with their compatibility entries, a manifest and service worker that make the
existing web property installable, and a plan for the install and uninstall moments on each
OS, which behave differently from a store app. A Progressive Web App is a web application
that the OS installs and launches like a platform-specific app; it ships through the URL,
updates on the next load, and runs in the engine of the browser that installed it.

You need the native app's feature list, a web version of the product (or the decision to build
one), and a domain served over HTTPS.

## Inventory native features against web capabilities

List every OS integration the native app relies on and look up each on this site before
promising it: push notifications ([Web Push](/reference/notifications/web-push/)), app icon
badges ([Badging](/reference/installation/badging/)), sharing into the app
([Share target](/reference/manifest/share-target/)), opening files
([`file_handlers`](/reference/manifest/file-handlers/)), payments
([Payment Request](/reference/capabilities/payment-request/)), and hardware such as
Bluetooth, USB, and NFC ([Capabilities](/reference/capabilities/)). Each entry's compatibility
table gives the per-browser, per-OS position with a verification date; the iOS Safari
row also covers Chrome, Edge, and Firefox on iOS, which embed WebKit there. Record three
columns per feature: web equivalent, platforms where it is missing, and the fallback you will
ship there. Features with no acceptable fallback are the reason to keep a native build for that
platform, and this inventory is the document that argument rests on.

## Make the web property installable

Two files turn the site into an installable app. The manifest supplies the identity and
launch metadata; MDN's installability guide lists the members Chromium browsers require as
`name` or `short_name`, `icons` with 192 px and 512 px entries, `start_url`, and `display`:

```json
{
  "id": "/",
  "name": "Field Notes",
  "short_name": "Notes",
  "start_url": "/?source=pwa",
  "scope": "/",
  "display": "standalone",
  "theme_color": "#1f4e79",
  "background_color": "#ffffff",
  "icons": [
    { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" }
  ]
}
```

The service worker is registered from the page and keeps the shell available offline, the
behaviour native users take for granted. The registration is feature-detected so the page
still loads in a browser without the API:

```js
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').catch((error) => {
    console.error('Service worker registration failed:', error);
  });
}
```

`/sw.js` itself precaches the shell on `install` and answers from cache on `fetch`;
[Getting started](/guides/getting-started/) contains a complete worker to copy. Manifest and
service worker are independent: Firefox desktop runs service workers but does not install from
a manifest (MDN: "Firefox does not support installing PWAs using a manifest file"), so verify
each on its own compatibility entry.

## Plan the install moment per OS

Store users are used to one install path; PWA install differs by OS and the migration page
must say so. MDN's installing guide documents the shapes: on desktop Chrome and Edge an install
icon appears in the URL bar when the page qualifies; mobile browsers put the command in the
browser menu; Safari on iOS installs through the "Add to Home Screen" UI, available from the
Share menu in Chrome, Edge, Firefox, and Orion too from iOS 16.4; on macOS 14 (Sonoma) Safari
adds **File** > **Add to Dock…**. MDN also notes that an installed PWA is tied to the browser
that installed it: a user who installs from Edge and later from Chrome has two copies. If the
native app stays on the stores during the transition, declare it in `related_applications`
and use `navigator.getInstalledRelatedApps()` (top-level secure context only) to hide the web
install promotion for users who still have it.

## Tell users how to launch and remove it

Launch behaviour matches a native app: MDN states that "clicking on the application icon
opens the PWA, even when the user is offline", in a standalone window without browser UI when
the manifest asks for it. Removal is where support tickets come from, so document it per OS
from MDN's guide: on desktop, the installed window's menu offers an uninstall link, and Chrome
lists installed apps at `chrome://apps` while Edge lists them at `edge://apps`; on most mobile
OSes a PWA uninstalls like any app from the apps settings.

:::observed
MDN's "Installing and uninstalling web apps" guide (read 2026-10-03) records that on iOS,
PWAs installed from Safari "are listed and searchable from the 'App Library' screen, but are
not listed along with other installed applications under 'Settings'", and that a long press
on the icon surfaces the delete-bookmark UI: removing the icon from the Home Screen deletes
the PWA. A migration FAQ that tells iOS users to look under Settings > General > iPhone
Storage, where native apps appear, sends them to a list the web app is not in.
:::

## See also

- [Getting started](/guides/getting-started/)
- [Make it installable](/guides/installable/)
- [Distribute a PWA via app stores](/guides/app-store-distribution/)
- [PWAs on iOS and Safari](/reference/platforms/ios-safari/)
- [Installing and uninstalling web apps](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Guides/Installing) (developer.mozilla.org)
- [Making PWAs installable](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable) (developer.mozilla.org)