Migration Guide: v0.13.x to v0.14.0
Non-native, compile-time only. This release removes the legacy
BackgroundLocationdefault export. There are zero runtime or native behavior changes -- only the shape of your imports. Your app will fail to build until the migration below is applied, but nothing can break silently at runtime.
TL;DR
Replace the default import and dotted call sites with named imports. For most codebases, a single find-and-replace is enough:
# 1. Delete every default import of the library
# find: import BackgroundLocation from '@gabriel-sisjr/react-native-background-location';
# action: remove, then add a named import at the top of the file (see step 4 below).
# 2. Strip the object prefix from every call site
# find: BackgroundLocation\.(startTracking|stopTracking|isTracking|getLocations|clearTrip|updateNotification)
# replace: $1
One-line GNU sed codemod for the call sites (safe on macOS with gsed, or Linux):
gsed -i -E 's/BackgroundLocation\.(startTracking|stopTracking|isTracking|getLocations|clearTrip|updateNotification)/\1/g' $(git ls-files '*.ts' '*.tsx')
BSD sed equivalent (macOS default sed):
find . -type f \( -name '*.ts' -o -name '*.tsx' \) -not -path '*/node_modules/*' \
-exec sed -i '' -E 's/BackgroundLocation\.(startTracking|stopTracking|isTracking|getLocations|clearTrip|updateNotification)/\1/g' {} +
Portable Node.js one-liner (no GNU/BSD split, works everywhere node is installed):
node -e "
const fs=require('fs'),path=require('path');
const walk=d=>fs.readdirSync(d,{withFileTypes:true}).flatMap(e=>{
const p=path.join(d,e.name);
if(e.isDirectory())return e.name==='node_modules'||e.name==='.git'?[]:walk(p);
return /\.(ts|tsx)$/.test(e.name)?[p]:[];
});
const re=/BackgroundLocation\.(startTracking|stopTracking|isTracking|getLocations|clearTrip|updateNotification)/g;
for(const f of walk('.')){
const before=fs.readFileSync(f,'utf8');
const after=before.replace(re,'\$1');
if(before!==after){fs.writeFileSync(f,after);console.log('updated',f);}
}
"
After the codemod, manually update the default-import line in each touched file to a named import (see Step-by-Step Migration).
Quick Migration Checklist
- Update
@gabriel-sisjr/react-native-background-locationto^0.14.0 - Run the sed / Node codemod above to strip
BackgroundLocation.prefixes - Replace every
import BackgroundLocation from ...with a named import list - Run
yarn typecheck-- any missed symbol will surface asCannot find name - Run the app on Android + iOS to confirm nothing changed at runtime (nothing should)
- Clear IDE caches if auto-import still suggests the old default (see Common Pitfalls)
Why This Changed
- Tree-shaking. The default export bundled all tracking methods into one object, forcing every consumer to pull the entire tracking API even if they only called
isTracking(). Named exports let modern bundlers (Metro with RAM bundles, Hermes bytecode, webpack in test environments) drop unused methods. For a typical app that only uses 3-4 methods, this is a measurable bundle-size win. - Consistency. Geofencing methods (
addGeofence,removeGeofence, etc.) shipped in v0.11.0 as named exports. Hooks (useLocationPermissions,useBackgroundLocation, etc.) have always been named exports. Mixing a default export with named exports forced consumers to remember two import styles and confused IDE auto-import. - Better IDE auto-import. VSCode and IntelliJ now auto-suggest
startTrackingfrom the top of the file, the same way they suggestuseStateor any other hook. No moreBackgroundLocation.prefix lookups. - Cleaner public API surface.
src/index.tsxis now a lean facade. All internal helpers (module probing, enum-to-string conversion, geofence validation, geofence serialization) moved tosrc/utils/.GeofenceErrormoved tosrc/errors/. None of that is user-facing, but it makes the library easier to reason about and audit.
No native (Android/iOS) code changed. Method signatures, return types, and runtime behavior are identical.
Before / After
Tracking Lifecycle
// Before (v0.13.x)
import BackgroundLocation from '@gabriel-sisjr/react-native-background-location';
const tripId = await BackgroundLocation.startTracking('delivery-42', {
accuracy: LocationAccuracy.HIGH_ACCURACY,
distanceFilter: 10,
});
const { active } = await BackgroundLocation.isTracking();
const points = await BackgroundLocation.getLocations(tripId);
await BackgroundLocation.stopTracking();
await BackgroundLocation.clearTrip(tripId);
// After (v0.14.0)
import {
startTracking,
stopTracking,
isTracking,
getLocations,
clearTrip,
LocationAccuracy,
} from '@gabriel-sisjr/react-native-background-location';
const tripId = await startTracking('delivery-42', {
accuracy: LocationAccuracy.HIGH_ACCURACY,
distanceFilter: 10,
});
const { active } = await isTracking();
const points = await getLocations(tripId);
await stopTracking();
await clearTrip(tripId);
Dynamic Notification Updates
// Before
import BackgroundLocation from '@gabriel-sisjr/react-native-background-location';
await BackgroundLocation.updateNotification(
'Delivery #42',
'Arriving in 5 min'
);
// After
import { updateNotification } from '@gabriel-sisjr/react-native-background-location';
await updateNotification('Delivery #42', 'Arriving in 5 min');
Geofencing
Geofencing methods were already named exports in v0.13.x. No change required. If your code already looks like this, it will keep working:
import {
addGeofence,
removeGeofence,
getActiveGeofences,
configureGeofenceNotifications,
GeofenceError,
GeofenceErrorCode,
} from '@gabriel-sisjr/react-native-background-location';
try {
await addGeofence({
identifier: 'warehouse-1',
latitude: -23.5505,
longitude: -46.6333,
radius: 150,
transitions: ['enter', 'exit'],
});
} catch (err) {
if (
err instanceof GeofenceError &&
err.code === GeofenceErrorCode.DUPLICATE_IDENTIFIER
) {
// handle duplicate
}
}
Hooks
Hooks were always named exports. No change required:
import {
useLocationPermissions,
useBackgroundLocation,
useLocationUpdates,
useLocationTracking,
useGeofencing,
useGeofenceEvents,
useGeofencePermissions,
} from '@gabriel-sisjr/react-native-background-location';
Error Handling
// Before
import BackgroundLocation from '@gabriel-sisjr/react-native-background-location';
try {
await BackgroundLocation.startTracking();
} catch (err) {
console.error(err);
}
// After
import { startTracking } from '@gabriel-sisjr/react-native-background-location';
try {
await startTracking();
} catch (err) {
console.error(err);
}
Step-by-Step Migration
A real upgrade from v0.13.x to v0.14.0 on a medium-sized app should take under 2 minutes. Here is the recipe.
-
Bump the dependency.
yarn add @gabriel-sisjr/react-native-background-location@^0.14.0# ornpm install @gabriel-sisjr/react-native-background-location@^0.14.0 -
Strip the
BackgroundLocation.prefix from every call site. Use the codemod from the TL;DR section. One command, global, reversible viagit. -
Replace every default import with a named import. The codemod leaves the
import BackgroundLocation from ...lines intact on purpose -- you need to decide which symbols to import per file. For each file that used to do:import BackgroundLocation from '@gabriel-sisjr/react-native-background-location';Replace it with the set of functions that file actually uses, for example:
import {startTracking,stopTracking,updateNotification,} from '@gabriel-sisjr/react-native-background-location';VSCode tip: delete the default-import line, then type a function name like
startTracking-- the auto-import suggestion will add the named import for you. -
Run the TypeScript checker. Any missed symbol or typo will surface as
Cannot find name 'BackgroundLocation'orCannot find name 'startTracking':yarn typecheck -
Rebuild and smoke test. Because no native behavior changed, a simple cold-start of the app on Android + iOS is enough:
yarn android # and/or yarn iosStart a trip, confirm points arrive, stop the trip. Done.
Common Pitfalls
A few gotchas that have been reported. If migration feels like it should be working but isn't, check here first.
-
Mixed default + named import on the same line. Before:
import BackgroundLocation, { useLocationPermissions } from '...';The codemod only touches call sites, not imports, so this line survives the sed pass but will break the build. Remove the default identifier and merge everything into the named list:import {useLocationPermissions,startTracking,stopTracking,} from '@gabriel-sisjr/react-native-background-location'; -
ESLint
import/no-default-export+ auto-fix keeps resurrecting the old import. If you had a custom ESLint rule or a shared config that auto-imports the default export on save, disable or remove it before running the codemod. Otherwise the save hook undoes your work. -
IDE auto-import still suggesting
BackgroundLocation. VSCode / WebStorm cache resolved module exports. If auto-import suggestions look stale after the upgrade:- VSCode:
Cmd+Shift+P->TypeScript: Restart TS Server - WebStorm:
File -> Invalidate Caches -> Invalidate and Restart
- VSCode:
-
Metro cache serving the old module shape. After the upgrade, if your app crashes with
undefined is not an object (evaluating 'BackgroundLocation.startTracking')at runtime (i.e. your codemod missed a site), restart Metro with a clean cache:yarn start --reset-cache -
CI builds passing locally, failing on the runner. Your local
node_modulesgot bumped but the runner's cache still has v0.13.x. Bust the CI cache key (e.g. rev the yarn.lock hash in your cache step) or clear the CI cache manually.
Affected Symbols
Every symbol that was previously accessed via the BackgroundLocation default export. All geofencing methods were already named exports in v0.13.x and are included here for completeness -- they need no code change in your app.
| Symbol | Before (v0.13.x) | After (v0.14.0) | Status |
|---|---|---|---|
startTracking | BackgroundLocation.startTracking(...) | import { startTracking } then startTracking(...) | Migrated |
stopTracking | BackgroundLocation.stopTracking() | import { stopTracking } then stopTracking() | Migrated |
isTracking | BackgroundLocation.isTracking() | import { isTracking } then isTracking() | Migrated |
getLocations | BackgroundLocation.getLocations(id) | import { getLocations } then getLocations(id) | Migrated |
clearTrip | BackgroundLocation.clearTrip(id) | import { clearTrip } then clearTrip(id) | Migrated |
updateNotification | BackgroundLocation.updateNotification(t, x) | import { updateNotification } then updateNotification(t, x) | Migrated |
addGeofence | import { addGeofence } (already named) | import { addGeofence } (unchanged) | No change |
addGeofences | import { addGeofences } (already named) | import { addGeofences } (unchanged) | No change |
removeGeofence | import { removeGeofence } (already named) | import { removeGeofence } (unchanged) | No change |
removeGeofences | import { removeGeofences } (already named) | import { removeGeofences } (unchanged) | No change |
removeAllGeofences | import { removeAllGeofences } (already named) | import { removeAllGeofences } (unchanged) | No change |
getActiveGeofences | import { getActiveGeofences } (already named) | import { getActiveGeofences } (unchanged) | No change |
getMaxGeofences | import { getMaxGeofences } (already named) | import { getMaxGeofences } (unchanged) | No change |
getGeofenceTransitions | import { getGeofenceTransitions } (already named) | import { getGeofenceTransitions } (unchanged) | No change |
clearGeofenceTransitions | import { clearGeofenceTransitions } (already named) | import { clearGeofenceTransitions } (unchanged) | No change |
configureGeofenceNotifications | import { configureGeofenceNotifications } (already named) | import { configureGeofenceNotifications } (unchanged) | No change |
getGeofenceNotificationConfig | import { getGeofenceNotificationConfig } (already named) | import { getGeofenceNotificationConfig } (unchanged) | No change |
GeofenceError | import { GeofenceError } (already named) | import { GeofenceError } (unchanged, now backed by src/errors/) | No change |
| All hooks | import { useBackgroundLocation } (always named) | Unchanged | No change |
| All enums | import { LocationAccuracy } (always named) | Unchanged | No change |
| All types | import type { TrackingOptions } (always named) | Unchanged | No change |
Internal Refactor (For the Curious)
src/index.tsx is no longer a catch-all. Internal helpers moved out:
src/utils/isNativeModuleAvailable.ts-- non-throwing TurboModule probe (simulator-safe)src/utils/moduleCheck.ts--assertNativeModuleAvailable()(throwing variant used by geofence methods)src/utils/trackingOptionsMapper.ts--toTrackingOptionsSpec()enum-to-string conversion for the Codegen bridgesrc/utils/geofenceValidation.ts--validateGeofenceRegion()runtime validationsrc/utils/geofenceSerialization.ts--prepareGeofenceRegion()/serializeGeofenceRegion()JSON helperssrc/utils/objectUtils.ts--extractDefinedProperties()generic utility consumed by hookssrc/errors/GeofenceError.ts--GeofenceErrorclass withGeofenceErrorCodediscriminator
All of these are internal and not part of the public API. Do not import from src/utils/* or src/errors/* directly -- the only stable surface is the package root, @gabriel-sisjr/react-native-background-location.
Need Help?
If the codemod misses a case or you hit a migration scenario not covered here:
- File an issue at github.com/gabriel-sisjr/react-native-background-location/issues
- Include the before/after of the failing import and the exact TypeScript error
- Tag with
migrationandv0.14.0
The migration is intentionally small in scope. If you are upgrading from an older version, go through v0.12.0 migration first, then apply this guide.