If you're building a React Native app and want to send push notifications, you'll run into two popular options: Expo Notifications and React Native Firebase Cloud Messaging (FCM). Both can get the job done, but they work differently and suit different types of projects.
Let's break them down in a simple way so you can pick the right one for your app.
What Are They?
Expo Notifications is a library that comes as part of the Expo ecosystem. It wraps both Apple Push Notification Service (APNs) and Firebase Cloud Messaging under one easy-to-use API. If you're already using Expo, this feels like a natural fit.
React Native Firebase Cloud Messaging (usually called @react-native-firebase/messaging) is a direct integration with Google's Firebase platform. It gives you full access to FCM's features and works in both bare React Native and Expo (with some setup).
Setup: Which One Is Easier?
Expo Notifications
Setting up Expo Notifications is pretty straightforward, especially if you're in a managed Expo workflow. Starting from Expo SDK 53, a development build is required to use remote push notifications.
npx expo install expo-notificationsYou don't need to touch native code at all in managed workflow. Expo handles the heavy lifting — certificates, provisioning profiles, and server keys — all through their dashboard.
For getting a push token:
1import * as Notifications from 'expo-notifications';
2
3const { status } = await Notifications.requestPermissionsAsync();
4const token = await Notifications.getExpoPushTokenAsync();
5console.log(token); // ExponentPushToken[xxxx]That ExponentPushToken is what you send to your backend to deliver notifications later through Expo's push service.
React Native Firebase
This one takes more effort to set up. You need to:
Create a Firebase project
Download google-services.json (Android) and GoogleService-Info.plist (iOS)
Install the package:
npm install @react-native-firebase/app @react-native-firebase/messaging4. Link the native modules and update your build.gradle and AppDelegate files
If you're using bare React Native, this is totally manageable. But if you're in a managed Expo workflow, you'll need to create a development build and add config plugins provided by React Native Firebase Team. Getting a token with Firebase:
1import messaging from '@react-native-firebase/messaging';
2
3await messaging().requestPermission();
4const token = await messaging().getToken();
5console.log(token); // Firebase FCM tokenSending Notifications
With Expo
Expo gives you a simple push API you can call from your server — no Firebase Admin SDK required:
1// From your backend (Node.js example)
2await fetch('https://exp.host/--/api/v2/push/send', {
3 method: 'POST',
4 headers: { 'Content-Type': 'application/json' },
5 body: JSON.stringify({
6 to: 'ExponentPushToken[xxxx]',
7 title: 'Hello!',
8 body: 'You have a new message.',
9 }),
10});It's quick and works well for most use cases.
With Firebase
You send notifications through Firebase's Admin SDK or the FCM REST API. This gives you more options and control:
1// From your backend using Firebase Admin SDK
2await admin.messaging().send({
3 token: 'fcm-device-token',
4 notification: {
5 title: 'Hello!',
6 body: 'You have a new message.',
7 },
8 data: {
9 screen: 'Chat',
10 userId: '123',
11 },
12});You get more flexibility here — like sending to topics, device groups, or conditions.
Handling Notifications in the App
Both libraries let you handle notifications when the app is in the foreground, background, or closed. But the approach is slightly different.
Expo Notifications
1// Foreground notification handler
2Notifications.setNotificationHandler({
3 handleNotification: async () => ({
4 shouldShowAlert: true,
5 shouldPlaySound: true,
6 shouldSetBadge: false,
7 }),
8});
9
10// Listen for incoming notifications
11useEffect(() => {
12 const subscription = Notifications.addNotificationReceivedListener(notification => {
13 console.log('Notification received:', notification);
14 });
15
16 return () => subscription.remove();
17}, []);React Native Firebase
1// Foreground handler
2useEffect(() => {
3 const unsubscribe = messaging().onMessage(async remoteMessage => {
4 console.log('Foreground message:', remoteMessage);
5 });
6
7 return unsubscribe;
8}, []);
9
10// Background/quit state handler (must be outside component)
11messaging().setBackgroundMessageHandler(async remoteMessage => {
12 console.log('Background message:', remoteMessage);
13});Feature Comparison
Feature | Expo Notifications | React Native Firebase |
|---|---|---|
Setup difficulty | Easy | Moderate to Hard |
Managed workflow support | Yes | Needs config plugin |
Custom notification sounds | Limited | Full support |
Topic messaging | No | Yes |
Analytics integration | No | Yes (Firebase) |
Data-only messages | Basic | Full support |
Local notifications | Yes | No (separate lib) |
Open source infrastructure | Expo-managed | Google Firebase |
Works without Expo account | No | Yes |
When to Use Expo Notifications
Go with Expo Notifications if:
You're using a managed Expo workflow and want the simplest path
You're building a small to medium app and don't need advanced FCM features
You want to avoid native code setup as much as possible
You need local notifications in addition to push notifications
You're prototyping or moving fast and want things to just work
When to Use React Native Firebase
Go with React Native Firebase if:
You're using bare React Native or have already ejected from Expo
You need topic-based messaging (e.g., subscribe users to channels)
You want Firebase Analytics tied to your notifications
You need full control over the notification payload and delivery
You're building an app where advanced FCM features matter (like data-only messages or silent pushes)
Can You Use Both Together?
Yes! Actually, they can complement each other. Expo Notifications can use FCM under the hood on Android. But mixing both libraries in one project can get confusing and may cause conflicts. It's usually better to pick one and stick with it.
A Quick Summary
Expo Notifications | Firebase Cloud Messaging | |
|---|---|---|
Best for | Expo projects, quick setup | Bare RN, advanced features |
Learning curve | Low | Medium |
Flexibility | Moderate | High |
Firebase required? | No | Yes |
Final Thoughts
There's no one-size-fits-all answer here. If you're starting fresh with Expo and want to move fast, Expo Notifications is the easier choice. If you're building something more complex or already using Firebase services in your app, React Native Firebase gives you more power and flexibility.
Think about your app's current setup, your team's experience, and what features you actually need — then go from there. Either way, both options are solid and well-maintained.


