---
title: Flutter Workmanager
description: Background task execution for Flutter apps
---

Execute Dart code in the background, even when your app is closed. Perfect for data sync, file uploads, and periodic maintenance tasks.

## Key Features

- **Background Task Execution**: Execute Dart code in the background on both Android and iOS platforms
- **Multiple Task Types**: Support for one-off tasks, periodic tasks, and iOS processing tasks  
- **Platform Constraints**: Configure network, battery, charging, and other constraints for task execution
- **Debug Support**: Built-in debugging with notifications to track background task execution

## Supported Platforms

| Platform | Support | Notes |
|----------|---------|--------|
| Android | ✅ Full | All WorkManager features supported |
| iOS | ✅ Full | Background Fetch + BGTaskScheduler APIs |
| macOS | ⚠️ Partial | One-off + periodic tasks via NSBackgroundActivityScheduler while the app is running (not after quit) |
| Web | ⚠️ Experimental | Service Worker + Web Worker based background execution (`workmanager_web`) — see [Web (experimental)](web) |
| Windows/Linux | ❌ Not supported | No background task APIs |

## Platform Capability Matrix

Not every feature behaves the same across platforms. The table below summarizes
what works where, so you can design your tasks around the capabilities of each
platform.

| Feature | Android | iOS | macOS | Web |
|---|---|---|---|---|
| One-off tasks (`registerOneOffTask`) | ✅ Scheduled by the OS; survives app restarts | ⚠️ Runs via `beginBackgroundTask` while the app is alive (foreground or shortly after backgrounding). Not guaranteed after the app is terminated | ⚠️ Runs via `NSBackgroundActivityScheduler` while the app is running/backgrounded and the Mac is awake. Tasks with no `initialDelay` run immediately; delayed tasks are best-effort | ⚠️ While the page is open: runs via Web Worker after `initialDelay`. While closed: best-effort on the next Service Worker wake after the deadline (periodic sync, push or fetch) |
| Periodic tasks (`registerPeriodicTask`) | ✅ Reliable, 15-minute minimum frequency | ⚠️ Best-effort. iOS decides when (and whether) background fetch runs, based on app usage; 15-minute minimum hint | ⚠️ Best-effort. `NSBackgroundActivityScheduler` decides timing; the Dart `frequency` is the interval hint | ⚠️ Experimental. Maps to Periodic Background Sync (Chromium, PWA installed + engaged, ~12h minimum); the Service Worker runs the compiled Dart dispatcher when the page is closed |
| Processing tasks (`registerProcessingTask`) | ❌ Not supported | ✅ BGProcessingTask (longer work, requires registration in AppDelegate) | ⚠️ Mapped to a one-off `NSBackgroundActivityScheduler` activity; network/charging constraints are ignored | ❌ Not supported |
| Health research tasks (`registerHealthResearchTask`) | ❌ Not supported | ⚠️ iOS 17+ only, via `BGHealthResearchTaskRequest`. Requires a Health Research Study container + `com.apple.developer.backgroundtasks.healthresearch` entitlement and user opt-in (see below) | ❌ Not supported | ❌ Not supported |
| `initialDelay` | ✅ Honored for one-off tasks. For periodic tasks it is best-effort (see below) | ⚠️ One-off: honored while the app stays alive. Periodic: used as the earliest-begin hint for BGTaskScheduler | ⚠️ Best-effort via the activity interval (0 = run as soon as possible); the system may defer the run | ⚠️ One-off: honored while the page is open (page timer); best-effort on the next Service Worker wake when closed |
| `inputData` | ✅ All supported types | ✅ Supported for one-off and periodic tasks | ✅ Supported for one-off and periodic tasks (captured at schedule time) | ✅ Supported (JSON-compatible values) |
| `taskName` in callback | ✅ The value you passed as `taskName` | ✅ One-off tasks receive the `taskName` you passed. Periodic/processing tasks receive the BGTaskScheduler identifier (the `uniqueName` you registered) | ✅ Tasks receive the activity identifier (the `uniqueName` you registered) | ✅ The value you passed as `taskName` |
| `frequency` | ✅ Configured from Dart | ❌ Configured in `AppDelegate.swift` via `registerPeriodicTask(withIdentifier:frequency:)` | ✅ Configured from Dart (interval hint) | ✅ Configured from Dart (browser clamps to the ~12h minimum) |
| Constraints (network, charging, battery) | ✅ Supported | ❌ iOS applies its own system-level constraints | ❌ Not supported (ignored) | ❌ Not supported |
| `cancelByUniqueName` / `cancelAll` | ✅ | ✅ Only cancels BGTaskScheduler requests (periodic/processing) | ✅ Invalidates scheduled activities | ✅ Removes tasks and unregisters periodic sync tags |
| `cancelByTag` | ✅ | ❌ Not supported (no-op) | ❌ Not supported (no-op) | ✅ Supported |
| Task execution after app is killed | ✅ Yes (one-off/periodic) | ❌ No — iOS does not run tasks after the app is terminated | ❌ No — the app process must be alive | ⚠️ Only when the browser wakes the Service Worker (periodic sync for installed/engaged PWAs, push, or an intercepted fetch) |
| Minimum run time budget | No hard limit, but WorkManager may defer work | ~30 seconds per task execution | No hard budget; the system may defer activities while the Mac is busy | Seconds — Service Worker wake-ups are short and browsers can terminate the worker at any time |

<Warning>
**Periodic `initialDelay` on Android:** WorkManager treats the initial delay of a
periodic task as a hint. Depending on the `androidx.work` version, the first run
may happen anywhere within the first interval rather than exactly after the
delay. If you need a task to run exactly once at a specific time and then repeat,
schedule a one-off task with the desired `initialDelay` and re-register the
periodic task from inside its callback.
</Warning>

<Warning>
**iOS one-off `initialDelay`:** The delay is honored only while the app remains
alive. iOS may suspend or terminate the app before the delay elapses, in which
case the task does not run. For work that must run later regardless, use a
processing task.
</Warning>

<Warning>
**macOS `callbackDispatcher` naming:** macOS cannot look up the dispatcher by
handle (there is no `FlutterCallbackCache` on macOS), so the callback function
must be a top-level function named exactly `callbackDispatcher` in your app's
main library (e.g. `main.dart`).
</Warning>

## iOS Background Task Strategies

iOS offers several scheduling strategies. Workmanager wraps the three
`BGTaskScheduler`-based strategies plus the legacy background-fetch path:

| Strategy | workmanager API | iOS version | Runtime budget | When the system runs it | Reliability |
|---|---|---|---|---|---|
| `BGAppRefreshTaskRequest` | `registerPeriodicTask` | 13+ | ~30 seconds | Periodically, based on app usage; at least 15 minutes between launches | Best-effort; no guaranteed interval; does not run on a schedule |
| `BGProcessingTaskRequest` | `registerProcessingTask` | 13+ | Minutes (typically 1–10, dynamically adjusted) | When the device is idle (often overnight, possibly while charging) | Best-effort but more generous than refresh; may be deferred or interrupted |
| `BGHealthResearchTaskRequest` | `registerHealthResearchTask` | 17+ | Minutes, like processing tasks | When the device is idle, with additional priority for study-essential processing | Higher priority/reliability than plain processing, but only for health-research apps (entitlement + study container + user opt-in) |
| `BGContinuedProcessingTaskRequest` | `registerContinuedProcessingTask` | 26+ | Starts in the foreground, continues in background | Immediately after submission, which must be a user action (e.g. button tap) | Continues as long as progress is reported (Live Activity + progress protocol); the system can terminate it abruptly under resource pressure |
| Background fetch (`performFetchWithCompletionHandler`) | iOS < 13 fallback (`Workmanager.iOSBackgroundTask`) | 7–12 | ~30 seconds | System-managed; typically ~once per day based on usage | Best-effort |

**Gaps in workmanager today:**

- `registerProcessingTask` on iOS currently delivers the task without the
  `inputData` captured at registration time (only one-off and periodic tasks
  persist input data). Health research tasks persist input data like periodic
  tasks.

### Health research tasks (`BGHealthResearchTaskRequest`)

`Workmanager().registerHealthResearchTask(...)` (iOS 17+) schedules a
`BGHealthResearchTaskRequest` — a subclass of `BGProcessingTaskRequest` that
iOS delivers with additional priority and reliability when the processing is
essential to a health research study the user participates in.

Apple enforces app-level requirements *before* such a task can be submitted or
delivered; the plugin cannot bypass them:

1. **Health Research Study container**: the app must be part of a HealthKit
   "Health Research Study" container (typically provisioned with ResearchKit /
   `HKResearchStudy`).
2. **Entitlement**: the `com.apple.developer.backgroundtasks.healthresearch`
   entitlement must be added to the app's `.entitlements` file (granted by
   Apple for approved research apps).
3. **User opt-in**: the user must have opted in to the study and remain a
   participant.
4. **Info.plist**: the task identifier must be listed in
   `BGTaskSchedulerPermittedIdentifiers` (same as processing tasks).

Without these, `BGTaskScheduler.shared.submit` fails and the plugin logs the
error (the Dart call still completes; check `printScheduledTasks` or logs).
The plugin registers the launch handler automatically at schedule time and
again on the next app launch; you only need
`WorkmanagerPlugin.registerBGHealthResearchTask(withIdentifier:)` in
`AppDelegate.swift` if you want to pre-register the handler.

<Info>
**Testing constraint:** BGHealthResearchTask delivery can only be validated on
a physical device with the health-research entitlement and an active study
container. The plugin code is iOS-17 availability-gated, but runtime
verification remains a TODO until tested by a health-research app.
</Info>

## Common Use Cases

| Use Case | Description |
|----------|-------------|
| **Sync data from API** | Automatically fetch and sync data from your backend API |
| **Upload files in background** | Upload photos, documents when network conditions are optimal |
| **Clean up old data** | Remove old files, cache data, and maintain app performance |
| **Fetch notifications** | Check for new notifications and messages from your server |
| **Database maintenance** | Perform database cleanup and optimization tasks |

## Architecture

This plugin uses a **federated architecture**:
- `workmanager` - Main package that provides the unified API
- `workmanager_android` - Android implementation using WorkManager
- `workmanager_apple` - iOS implementation using BGTaskScheduler + macOS implementation using NSBackgroundActivityScheduler
- `workmanager_platform_interface` - Shared interface for platform implementations

All packages are automatically included when you add `workmanager` to pubspec.yaml.

## Get Started

Ready to add background tasks to your Flutter app?

**[→ Quick Start Guide](quickstart)** - Get up and running in minutes

**[→ API Documentation](https://pub.dev/documentation/workmanager/latest/)** - Complete Dart API reference

## Example Project

See a complete working demo: **[Example App →](https://github.com/fluttercommunity/flutter_workmanager/tree/main/example)**
