# Manifest file_handlers

> How the file_handlers manifest member registers an installed PWA as an OS-level handler for specific file types, and how window.launchQueue delivers the opened file to your app code.

**In one line:** `file_handlers` is an array of objects that registers an installed PWA with the operating system as a handler for a given set of file types, so opening a matching file launches the app — the app then reads the file via `window.launchQueue` in its own JavaScript.

## Syntax

```json
{
  "file_handlers": [
    {
      "action": "/handle-audio-file",
      "accept": {
        "audio/wav": [".wav"],
        "audio/x-wav": [".wav"],
        "audio/mpeg": [".mp3"],
        "audio/mp4": [".mp4"],
        "audio/aac": [".adts"],
        "audio/ogg": [".ogg"],
        "application/ogg": [".ogg"],
        "audio/webm": [".webm"],
        "audio/flac": [".flac"],
        "audio/mid": [".rmi", ".mid"]
      }
    }
  ]
}
```

Each object in the `file_handlers` array requires:

| Property | Required | Description |
|---|---|---|
| `action` | Yes | The URL to navigate to when a file is handled. Must be within the PWA's navigation scope, which defaults to `start_url` but can also be set with `scope`. |
| `accept` | Yes | An object whose keys are MIME types and whose values are arrays of file-extension strings associated with that MIME type. |

## Registration only launches the app — you still handle the file

`file_handlers` registers the PWA with the OS so opening a matching file launches it, but the PWA itself must then handle the file in JavaScript: "this only results in the operating system launching the PWA when a matching file is opened. The PWA then needs to actually handle the file using JavaScript code." Other applications may also be registered for the same file types, and how the OS lets the user choose between handlers varies by device.

## Reading the file with window.launchQueue

Handling files is done in the application code that runs on the main thread, not in the service worker. Use `window.launchQueue.setConsumer()` to read the files passed to the launch:

```js
async function playSong(handledFile) {
  const blob = await handledFile.getFile();
  const url = window.URL.createObjectURL(blob);
  const audio = new Audio(url);
  audio.play();
}

if ("launchQueue" in window) {
  window.launchQueue.setConsumer((launchParams) => {
    if (launchParams.files && launchParams.files.length) {
      playSong(launchParams.files[0]);
    }
  });
}
```

## Single vs. multiple file launches

The `launch_type` property controls whether opening several files at once opens them in a single client or in multiple clients; the default is `"single-client"`. When set to open in multiple clients, each launch is separate, and for each launch the `LaunchParams.files` array has just one element. This field is subject to platform limitations: Windows never launches an app with multiple files, but instead launches a single app multiple times with one file each, so `launch_type` has no effect there and all launches are effectively `"multiple-clients"`.

## A permission prompt gates access

When the File Handling API opens a file, a permission prompt is shown before the PWA can view it, appearing right after the user selects the PWA to open the file. This permission prompt shows every time until the user clicks Allow or Block, or ignores the prompt three times. When the manifest updates and changes in the `file_handlers` section are detected, the permissions are reset. Users can also change file-type associations at the OS level, outside the browser's control.

## Platform support

File Handling is currently limited to desktop operating systems and is Chromium-only: Chrome 102+ and Edge 102+ support it; Firefox and Safari do not.

## Practical checklist

- [ ] Each `action` URL is within the PWA's navigation scope.
- [ ] `accept` lists every MIME type and extension your handler supports.
- [ ] `window.launchQueue.setConsumer()` is guarded with `"launchQueue" in window` before use.
- [ ] File reading happens in page/app code, not the service worker.
- [ ] `launch_type` is set deliberately if you need multiple files to open in separate clients.
- [ ] You have tested opening a matching file from the OS file manager after installing the PWA on a supported desktop browser.

## Try it

The companion demo at [/demo/#file-handling](/demo/#file-handling) declares `file_handlers` for `.txt` and `.md` in its manifest, consumes `window.launchQueue` on load, and opens the same file types through `showOpenFilePicker()` from a button. It reads only the file name and size.

## Cross-references

- [Manifest shortcuts](/reference/manifest/shortcuts/) — another manifest member that adds OS-level entry points to an installed PWA