Have you ever needed your Flutter app to keep running tasks even when it isn’t open on the screen? For example, a chat app that checks for new messages, or a fitness app that continues to track steps while minimized. If that sounds like your use case, then you might want to use Flutter background services.
These services allow your app to execute Dart code outside the main UI, so tasks like syncing data, sending notifications, or monitoring events can continue without blocking the interface.
Note: The code examples in this article are simplified for explanation and learning purposes. They are not production-ready and should be treated as a reference only.
What Are Background Services in Flutter?
A background service is a task that keeps running even when the app is not in the foreground. In Flutter, this is achieved either by using isolates, which are independent Dart execution threads, or by relying on plugins that handle platform-specific background execution.
Confused about which kind of background task fits your use case? Knowing the difference is important because Flutter offers multiple ways to keep work running when the app isn’t active, and each option is suited for specific scenarios:
Foreground services: These are long-running tasks that remain active even when the app is minimized, such as playing music or recording location data. They often show a persistent notification on Android to indicate they are running.
Background isolates: These run in a separate Dart isolate, which is like a lightweight thread that doesn’t share memory with the main app. Isolates are suitable for tasks such as syncing data, periodic background fetches, or processing heavy computations without freezing the UI.
For scheduled jobs that need to persist across app restarts or device reboots, developers often use the workmanager plugin, which integrates with Android’s WorkManager and iOS background fetch APIs.

Implementing a Background Service in Flutter
The easiest way to get started is with the flutter_background_service plugin. It allows you to run Dart code in the background and manage tasks without blocking the main app. To start, first, add the dependency:
dependencies:
flutter_background_service: ^latest
Then initialize the service in your main.dart:
import 'package:flutter/material.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await FlutterBackgroundService.initialize(onStart);
runApp(MyApp());
}
void onStart(ServiceInstance service) {
service.on('stopService').listen((event) {
service.stopSelf();
});
// Example: log a message every 5 seconds
Timer.periodic(Duration(seconds: 5), (timer) {
print("Background service is running: ${DateTime.now()}");
});
}
In this example, the service is initialized before the app starts, and the onStart callback defines the background work. Inside onStart, we listen for events like stopService so the task can be cancelled if needed.
The Timer.periodic call is a simple demonstration of background execution. It logs a message every five seconds, even if the app is minimized or the UI is inactive. The important detail here is that the work runs in a separate background instance, meaning it doesn’t block the main thread or affect the app’s responsiveness.
Why Platform Setup?
To get background services running on real devices, you need extra platform configuration:
Android: Add the following to your AndroidManifest.xml:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
Also, foreground services must display a persistent notification. Otherwise, Android may kill them. For iOS, in Xcode, enable Background Modes under app capabilities and select the required options, such as Background fetch or Background processing.
What’s Flutter WorkManager?
But flutter_background_service isn’t the only option. The WorkManager plugin is also useful for tasks that don’t need to run constantly but should be scheduled reliably, even after the app restarts. It is especially useful for jobs like syncing data at intervals or performing cleanup tasks.
Start by adding the dependencies first:
dependencies:
workmanager: ^latest
Here’s a quick example with the workmanager package:
import 'package:flutter/material.dart';
import 'package:workmanager/workmanager.dart';
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) {
print("Running background task: $task");
return Future.value(true);
});
}
void main() {
WidgetsFlutterBinding.ensureInitialized();
Workmanager().initialize(callbackDispatcher, isInDebugMode: true);
Workmanager().registerOneOffTask("task1", "simpleTask");
runApp(MyApp());
}
Here, the callbackDispatcher defines what should run in the background, while registerOneOffTask schedules it. Unlike flutter_background_service, which is continuous, WorkManager tasks are scheduled and run at defined times.
Note: On iOS, WorkManager only supports background fetch and cannot schedule tasks as flexibly as Android.
Wrapping Up
Background services should be used wisely, since they can drain battery and system resources. Always account for platform differences: Android offers more options while iOS is stricter. As a best practice, keep your users informed through notifications and allow them to stop background tasks when needed.
Beyond flutter_background_service and workmanager, there are also platform schedulers like Geofencing for location-based triggers, Alarm Manager for precise alarms, and JobService for condition-based jobs. Firebase JobDispatcher has been replaced by WorkManager, but it is worth knowing if you maintain older projects.
By picking the right tool for the right task, you can ensure your Flutter app stays responsive while still performing important background work.