# flutter_background_fetch: fifteen-minute wake-ups, and what the OS does to them

> The background_fetch plugin gives a Flutter app a callback roughly every fifteen minutes on iOS and Android, and its most valuable content is not the API but the platform caveats it documents. The README is unusually blunt about the limits: you can never get an event faster than fifteen minutes, the operating system throttles you, iOS stops firing entirely once the app is terminated, and it can take days before iOS starts firing regularly.

**transistorsoft/flutter_background_fetch** — Periodic callbacks in the background for both IOS and Android.  Includes Android Headless mechanism

- Repository: https://github.com/transistorsoft/flutter_background_fetch
- Stars: 596 · Forks: 171
- Language: Dart
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/transistorsoft-flutter-background-fetch

## What the plugin actually does

Background Fetch is described as a very simple plugin which attempts to awaken an app in the background about every 15 minutes, providing a short period of background running time. The plugin executes your provided callbackFn whenever a background-fetch event occurs.

That is the entire concept, and its simplicity is the point. The plugin is not a work scheduler with priorities, dependencies or queues. It is a way to get your Dart code a small amount of execution time on a schedule the operating system is willing to grant, which is a much narrower thing than the phrase periodic background tasks suggests to most people.

The package is by Transistor Software, the creators of Flutter Background Geolocation, and it is published on pub.dev as background_fetch. The primary language is Dart, the licence is MIT with the copyright held by Chris Scott and Transistor Software, the last push was on 2026-05-25 with the project not archived, and the repository publishes no GitHub releases.

The repository layout shows a conventional Flutter plugin with an android/ and an ios/ directory for the native sides, a lib/ directory for the Dart API, an example/ directory that is a full Flutter app rather than a snippet, a help/ directory, and pubspec.yaml, analysis_options.yaml and a CHANGELOG.md. There is a CLAUDE.md at the root as well, which suggests the project has some tooling conventions in place for automated contributors.

The more recent addition the README highlights is a scheduleTask method for scheduling arbitrary one-shot or periodic tasks, which is the part of the API that moves beyond the fixed fifteen-minute rhythm.

## The fifteen-minute ceiling is a hard limit, not a default

The single most important sentence in the README is the one that says there is no way to increase the rate at which a fetch event occurs, that the plugin sets the rate to the most frequent possible, and that you will never receive an event faster than 15 minutes.

The wording is careful. The plugin does not schedule events every fifteen minutes. It requests that the operating system grant background execution at the most frequent rate the platform allows, and the platform then throttles that request based on usage patterns. So the fifteen minutes is a ceiling on the request, and the actual interval is a function of the operating system's judgement about your app and the user.

The example the README gives is a phone that has not been switched on for a long period, in which case fetch events will occur less frequently. On iOS, if the user disables background refresh, they may not happen at all.

This has a direct consequence for how you design around the plugin. Any logic that assumes a fifteen-minute heartbeat will drift, and the drift is not bounded by the plugin but by the operating system's scheduling policy, which you cannot query and cannot override. The design implication is that the callback has to be idempotent and has to tolerate a long gap, because a long gap is normal rather than exceptional.

It also means the plugin is the wrong tool if your requirement is a specific interval. The README is candid that the rate cannot be increased, so an application that needs, say, a check every two minutes has to use something else, and a team that discovers this after building on the plugin has wasted a layer of abstraction.

The right framing is that background_fetch gives you a periodic opportunity to do a bounded amount of work, on the operating system's schedule, with the operating system's permission. Design the work around that, and the plugin does its job.

## iOS: terminated means stopped, and the machine learning takes days

The iOS section is a list of constraints that any team evaluating this plugin should read before promising a schedule to a stakeholder.

The first is the one that changes application architecture. When your app is terminated, iOS no longer fires events, and there is no such thing as stopOnTerminate: false for iOS. That option exists elsewhere in the plugin's configuration surface, but on iOS it cannot deliver what it suggests, and a background job that silently stops when the user swipes the app away is not a background job.

The second is timing. iOS can take days before Apple's machine-learning algorithm settles in and begins regularly firing events, and the README explicitly says not to sit staring at logs waiting for an event to fire. Its advice on this is practical: if your simulated events work, that is all you need to know that everything is correctly configured. The documentation links a page on debugging with simulated events, and that is the correct way to verify your setup rather than waiting for a real one.

The third is the long-absence case. If the user does not open your iOS app for long periods of time, iOS will stop firing events. Combined with the termination rule, that means an iOS application can go entirely silent for a user who has not touched it, and the only reliable way to reach that user is a push notification that brings them back into the app.

The fourth constraint is on the newer scheduleTask method, and it is a sharp one: on iOS it seems only to fire when the device is plugged into power. That is a useful, if restrictive, escape hatch. For tasks where delay is acceptable but a prompt start is not, such as a background sync that can wait until the phone is charging overnight, that behaviour is usable. For anything user-facing it is not.

So on iOS the practical design rule is: use the fifteen-minute fetch while the app is in the foreground or backgrounded, assume nothing after termination, and use push to bring a dormant user back.

## Android: the Headless mechanism is the differentiator

The Android section is one line long, and it describes the feature that makes the Android side of this plugin genuinely different from the iOS side: the Android plugin provides a Headless implementation allowing you to continue handling events even after app-termination.

That is the opposite of the iOS behaviour, and it is the reason to use this plugin rather than writing your own platform channel calls. A Headless service in the Android sense is a service that can be started by the system without the user launching the application, and it can run a background job with the application process not in the foreground. For a plugin whose entire purpose is background execution, the difference between continuing to receive events after termination and never receiving them again is the difference between a working feature and a broken one.

The configuration for it is a single option, enableHeadless, documented in the API reference. The README points at the BackgroundFetchConfig page for the details, and the whole set of API documentation, the setup guide, the examples and the debugging guidance live on a separate documentation site rather than in this repository.

The Android caveat is the same one that applies to the iOS side and to every background scheduler on Android: the operating system throttles background work based on the app's usage, so a user who barely opens the application will see fewer events. The plugin cannot change that, and the README does not claim otherwise. What it can do is keep firing after the app is terminated, and on Android that is a better guarantee than iOS offers.

## How to use it, and how to test it

The README is not a tutorial, and it says so by linking out. There is a setup guide, an API documentation page, an examples page, a debugging page, and an example app in the example/ directory of this repository.

The API surface, from what the README shows, is small. You configure a BackgroundFetchConfig, and the important knobs are the ones the caveats above refer to. The enableHeadless option controls the Android headless mechanism, and there is a stopOnTerminate setting whose iOS behaviour is effectively fixed regardless of its value. The plugin is invoked through a callbackFn that runs when an event occurs, and the scheduleTask method adds one-shot and arbitrary periodic scheduling on top of the built-in rhythm.

Testing is where most of the practical work sits, and the documentation links a dedicated debugging page along with simulated events. The reasoning the README gives is the right one to follow: since a real event can take days to arrive on iOS, verification has to happen through simulated events, and the simulated path exercising the same code means a passing simulation tells you the configuration is correct.

The example/ directory in the repository is a full Flutter application rather than a code fragment, with its own android/ and ios/ directories, its own pubspec.yaml, a test/ directory and a test_driver/ directory. That is the artefact to start from if you want a working integration, since the alternative is wiring the plugin into an application and discovering the platform differences by trial.

The scripts/ directory at the repository root and the CHANGELOG.md are the other places to look, the first for the release tooling and the second for the history of platform behaviour changes, which in a plugin whose value depends on what the operating system does is the most useful file in the repository.

## The honest evaluation

The plugin does one thing, does it on two platforms, and spends most of its documentation on the limits of the thing it does. That is a well-shaped tool for a narrow problem.

Adopt it if your application needs a periodic opportunity to do a bounded amount of work, you accept the operating system's scheduling as the authority on when that happens, and you can live with a callback that might arrive in ten minutes or in ten hours. It is well suited to things like periodic sync of a small cache, a check against a server for changed state, or a light housekeeping task. The Android headless mode makes it genuinely more useful than a naive platform-channel implementation for a significant part of that list.

Do not adopt it if the schedule is a product requirement, because it is not one. The fifteen-minute ceiling and the operating system throttling mean the interval is a suggestion the platform may revise. Do not adopt it on iOS for anything that must survive the user closing the app, and do not rely on scheduleTask on iOS for prompt work, since it appears to fire only on power. And do not adopt it if your design needs a guaranteed sequence of wake-ups, because a gap of days is within the documented behaviour of the platform rather than a fault in your integration.

The comparison worth making is with the alternatives. A push-notification-driven design, where the server tells the app when there is work, is more reliable and more controllable, at the cost of server involvement and the usual notification permission friction. A foreground service on Android is more immediate and more expensive in battery and user tolerance. What background_fetch gives you is the simplest possible mechanism with no server dependency and no foreground service, and on Android it survives termination.

For a Flutter team that needs a periodic background poke and understands that the timing is not in its hands, that is a reasonable package. The documentation, which tells you the bad news clearly, is the strongest argument for it.

## Conclusion

Adopt flutter_background_fetch if your Flutter app needs a periodic background opportunity to do a bounded amount of work, and you accept that the operating system decides when, with the Android headless mode giving you continued callbacks after the app is terminated. Do not adopt it when the interval is a product requirement, when the work must survive an iOS user closing the app, or when you need prompt execution on iOS, because the documented ceiling of fifteen minutes and the platform throttling mean the timing is never yours to promise. Before you commit, read the iOS and Android sections of the README in full rather than the API page, set up the example application in the repository as a working integration, and verify your configuration with the simulated events in the debugging documentation instead of waiting for a real callback that may take days to arrive on iOS.

## FAQ

### How often does the background_fetch plugin fire on iOS and Android?

It attempts to awaken the app about every 15 minutes, which is the most frequent rate the plugin can request. You can never receive an event faster than 15 minutes, and the operating system throttles the actual rate based on usage patterns, so a phone unused for a long period will see fewer events, and on iOS disabling background refresh stops them entirely.

### Does background_fetch work after the app is terminated?

On Android, the plugin provides a Headless implementation, controlled by the enableHeadless option, that continues handling events even after app termination. On iOS it does not: the README states that iOS no longer fires events when the app is terminated and that there is no such thing as stopOnTerminate: false for iOS.

### Why do I not get background fetch events on iOS?

iOS can take days before Apple's machine-learning algorithm settles in and begins regularly firing events, and if the user has not opened the app for long periods iOS stops firing events altogether. The README's advice is to use the simulated events in the debugging documentation: if those work, the configuration is correct.

### What does the scheduleTask method in background_fetch do?

It schedules arbitrary one-shot or periodic tasks on top of the built-in fifteen-minute rhythm. The README notes that on iOS it seems only to fire when the device is plugged into power, which makes it usable for work that can wait overnight but not for prompt user-facing tasks.

### Who maintains flutter_background_fetch and under what licence?

It is by Transistor Software, the creators of Flutter Background Geolocation, and is published on pub.dev as background_fetch. It is MIT licensed with the copyright held by Chris Scott and Transistor Software, and the last push to the repository was on 2026-05-25.

## Sources

- [Issues](https://github.com/transistorsoft/flutter_background_fetch/issues)
- [License: MIT](https://github.com/transistorsoft/flutter_background_fetch/blob/master/LICENSE)
- [README](https://github.com/transistorsoft/flutter_background_fetch/blob/master/README.md)
- [transistorsoft/flutter_background_fetch on GitHub](https://github.com/transistorsoft/flutter_background_fetch)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/transistorsoft-flutter-background-fetch
