react-native-background-actions runs JavaScript while your app is closed
React Native background service library for running background tasks forever in Android & iOS.
At a glance
- What is it?
- react-native-background-actions schedules a JavaScript task that keeps running in the background on Android and iOS, but the platform rules are the real story: Android relies on HeadlessJS and a mandatory notification, while iOS relies on a short background task window unless another library holds the app alive. The 4.x line requires a recent Android target SDK.
- Who is it for?
- Adopt react-native-background-actions for a continuous foreground-style job such as location tracking or a long transfer, and plan around the platform rather than around the library, because Android needs a visible notification and a recent target SDK while iOS only grants a limited background window.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A promise the operating systems only partly allow
react-native-background-actions is a React Native library for running background tasks in Android and iOS, and its description is blunt about the intent: schedule a background job that will run your JavaScript when your app is in the background or foreground.
The target use is a long running job inside a mobile app, the kind of thing that needs a service rather than a screen. A user should not have to keep the app in the foreground, and on Android the job should survive the app being closed entirely.
The interesting part of the library is not the API but the two very different platform stories it has to tell, and it tells both in a warning block at the top of the documentation rather than burying them.
On Android the library relies on React Native's HeadlessJS, and the jobs will run even if the app has been closed. In Android 12 and later you cannot launch background tasks from the background, and a notification is shown while the task runs, with the note that it is not possible to start the service without it. That notification is visible only on Android.
On iOS the library relies on UIApplication beginBackgroundTaskWithName, which the documentation is explicit will not keep your app in the background forever by itself. The suggested way around that is to rely on other libraries, for example react-native-track-player, that use audio or geolocation to keep the app alive while you execute the JavaScript from this library.
That second point deserves emphasis. On iOS this library is not a solution on its own but a component you combine with something else.
HeadlessJS on Android and the notification that comes with it
The Android mechanism is React Native's own HeadlessJS, and the library builds on it rather than reimplementing a service.
HeadlessJS runs JavaScript with no UI attached, which is exactly the shape of the work this library wants to do. The library adds the scheduling, the notification and the option handling around it. Before you build the task, the documentation asks you to read the HeadlessJS documentation itself, since the semantics of the task, including how it is invoked and when it runs, are defined there.
The Android 12 restriction is the part that shapes application design. Because you cannot launch background tasks from the background, the task has to be started while the app is in the foreground, and because the service cannot run without a notification, the user sees a persistent notification entry for as long as the job runs. There is no way to suppress it.
That is a reasonable trade for the platform, since a persistent notification is what lets a user see and stop a long running job, but it does mean an app built on this library always shows something in the shade. The options that configure that notification, including its title, description, icon and colour, are part of the public API rather than an implementation detail.
The iOS path and its documented escape hatch
iOS is where the library is honest about its limits.
The mechanism is UIApplication beginBackgroundTaskWithName, which grants a bounded amount of time for your app to finish work after it leaves the foreground. The documentation states plainly that this will not keep your app in the background forever by itself. Any code that assumes an infinite loop survives on iOS alone is assuming something the platform will not deliver.
The workaround the project points at is compositional rather than technical. Other libraries, react-native-track-player being the named example, use audio or geolocation to keep the app alive in the background, and while they do that, the JavaScript scheduled by this library keeps running.
That means an iOS implementation of a long running background job here has at least two moving parts, and the second part is what keeps the process alive. It also has consequences at review time, since an app that plays audio in the background for a non-audio reason may be questioned, and a location library used only to hold the process alive has its own permission prompts.
The API reference notes that updateNotification is an Android only call and that iOS will ignore it, and that iOS will also run everything in the background until stop is called. So the two platforms share a surface but not a behaviour, which is worth keeping in mind when you write shared code around it.
Writing the task and starting it
The usage shape is a task function, an options object, and a call to start.
The task is an async function that receives the parameters you passed in, and it may do anything as long as it does not touch UI:
const veryIntensiveTask = async (taskDataArguments) => {
// Example of an infinite loop task
const { delay } = taskDataArguments;
await new Promise( async (resolve) => {
for (let i = 0; BackgroundService.isRunning(); i++) {
console.log(i);
await sleep(delay);
}
});
};The loop is driven by BackgroundService.isRunning(), which is how the task learns that the service has been stopped, rather than by a flag you set yourself. The documentation also notes that once your task completes, React Native will go into paused mode, unless there are other tasks running or there is a foreground app.
The options object carries the identity of the task and the notification that represents it on Android:
const options = {
taskName: 'Example',
taskTitle: 'ExampleTask title',
taskDesc: 'ExampleTask description',
taskIcon: {
name: 'ic_launcher',
type: 'mipmap',
},
color: '#ff00ff',
linkingURI: 'yourSchemeHere://chat/jane', // See Deep Linking for more info
parameters: {
delay: 1000,
},
};Then start, update and stop:
await BackgroundService.start(veryIntensiveTask, options);
await BackgroundService.updateNotification({taskDesc: 'New ExampleTask description'}); // Only Android, iOS will ignore this call
// iOS will also run everything here in the background until .stop() is called
await BackgroundService.stop();Three warnings come with those calls and they are behavioural, not stylistic. If you call stop on a background service, no new tasks will be able to be started. Do not call start twice, as it will stop performing previous background tasks and start a new one. And if start is called on the background, it will not have any effect.
That last one is worth internalising. On Android, the task cannot be launched from the background at all.
The notification contract, deep links and the expiration event
The options table makes the platform split explicit at the property level. taskName is the identifier used for the task, used for identification. taskTitle, taskDesc and taskIcon are marked as Android required, since they describe the notification that must be shown. The colour defaults to the string "#ffffff", and the task icon carries a name and a type, with the example using the mipmap type and the ic_launcher name from the Android resource system.
The linkingURI property is the link called when the notification is clicked, with the example "yourSchemeHere://chat/jane". This is a practical feature rather than a cosmetic one: a background job that surfaces a notification is far more useful if tapping it opens the screen the user was trying to reach, and the deep linking section of the documentation covers how to wire that up in the app.
The parameters object is how you hand data into the task. In the example it carries a delay of 1000, and the task reads it from the arguments it receives. Since the task may start when the app is not running, these parameters are often the only channel through which the job learns what it was asked to do.
The documentation also lists an expiration event among its topics, which is the hook for the case where the platform ends the granted background time. That event is the safety net for iOS, where a task that outlasts its background window needs to be told rather than assumed.
On the code side, the package exposes its entry point as src/index.js, ships type declarations built into lib/types/index.d.ts, and includes a podspec for the iOS side, so a CocoaPods install is part of the setup rather than something the library handles for you.
Version constraints and the gap between releases
The compatibility table is where most upgrade pain in this library lives.
For an Android targetSdkVersion lower than 31, which was introduced in React Native 0.68.0, you need to upgrade before attempting to use the latest version. The table itself lists the 4.X.X line as requiring an Android target SDK of 34 or above, the 3.X.X line as requiring 31 or above, and the 2.6.7 line with the values left as unknown.
The React Native and iOS version columns in that table are listed as unknown for every row, which is a bit of a hole in the documentation. The only React Native constraint stated elsewhere is the peer dependency in package.json, react-native at 0.47.0 or newer, which is a much lower floor than the Android target SDK requirement implies. In practice the Android requirement is the binding one, since the 4.x line needs target SDK 34.
The release history shows a project that moves in steps. Version 4.0.0 landed on 2024-06-17, 4.0.1 on 2024-07-09 and 4.1.0 on 2026-04-07, and that last push was also on 2026-04-07. In other words the most recent change to the library is about six months old at the time of writing, and the 4.0 line before it sat for close to two years. That gap matters for anyone planning a dependency, because the 4.1.0 release is the first one to carry a change since the 4.x line settled.
Installation itself is delegated. The README sends you to INSTALL.md for the installation steps, the compatibility notes and the linking process, so the details of autolinking and manual linking live in a separate file rather than on the main page.
Where the library fits, and where it does not
The realistic use is a job that is genuinely continuous and user visible: recording a track while driving, uploading a large file, keeping a location trace. In that case the Android notification is a feature, and the iOS audio or geolocation companion is an acceptable price.
The unrealistic use is anything that assumes a quiet, unnoticeable background process on iOS, which the platform will not grant, or anything scheduled from the background on Android 12 and later. Both of those are stated in the documentation rather than discovered in production, which is to the credit of the project.
The alternative to this library is not another package but a different design. Writing the service natively in the Android and iOS applications, so you own the foreground service type, the permission declarations and the exact behaviour, removes the dependency and the compatibility ceiling. It costs a native module and two implementations, and it means you deal with the platform rules directly instead of through a React Native layer.
A second alternative is to not run a continuous job at all, and to use scheduled work instead, which fits the many use cases that only need periodic wake-ups rather than a job that never stops. The library's own design, with an isRunning loop and a start and stop pair, is built for the first case and does not try to cover the second.
The project itself is MIT licensed, with the LICENSE file in the repository root, and the package manifest declares the same. The repository is not archived, and the author field points to a single maintainer, so the bus factor is one person, which for a library tied to platform behaviour is a factor to weigh.
Editorial conclusion
Adopt react-native-background-actions for a continuous foreground-style job such as location tracking or a long transfer, and plan around the platform rather than around the library, because Android needs a visible notification and a recent target SDK while iOS only grants a limited background window. Verify first that your app can satisfy the Android 34 target SDK and the notification requirement, and decide deliberately whether the iOS workaround of holding the app alive with an audio or geolocation library is acceptable in your review process.
Frequently asked questions
How do I install react-native-background-actions?
The README points to INSTALL.md for the installation steps, the React Native compatibility notes and the linking process. On the iOS side the package ships a podspec, and the repository's package.json provides a pods script that runs cd ios && pod install.
Can react-native-background-actions keep running forever on iOS?
Not on its own. The library relies on UIApplication beginBackgroundTaskWithName, which the documentation says will not keep your app in the background forever. The project suggests combining it with a library such as react-native-track-player, which keeps the app alive using audio or geolocation.
What are the Android version requirements for react-native-background-actions?
The 4.X.X line requires an Android target SDK of 34 or above, and the 3.X.X line requires 31 or above. If your targetSdkVersion is lower than 31, introduced in React Native 0.68.0, you must upgrade before using the latest version.
Will the background notification show on iOS with react-native-background-actions?
No. The documentation states that the notification will only be visible in Android, and that updateNotification is an Android only call which iOS will ignore. A notification is required on Android and the service cannot start without it.
What happens if I call stop or start twice with react-native-background-actions?
Calling stop means no new tasks will be able to be started. Calling start twice stops the previous background tasks and starts a new one. And if start is called while the app is on the background, it will not have any effect.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rapsssito-react-native-background-actions)Was this useful?