To get push notifications in Flutter, add firebase_messaging, ask the user for permission, register the device with Firebase Cloud Messaging (FCM), send the device's ID to your server, and then send messages from the Firebase console or your backend. On iOS you also upload an APNs key to Firebase first.

This guide is for Flutter developers with a Firebase project. It uses firebase_messaging 17.0.0, published by firebase.google.com on 15 October 2026. The running example is a bakery app that tells a customer "Your order is ready".

In short:

  • Firebase now recommends the Installation ID (FID) over the old registration token.
  • Foreground notifications are not shown by default on Android or iOS.
  • A background handler must be a top-level function with @pragma('vm:entry-point').
  • Android 13 and newer, iOS, macOS and web all need explicit permission.

Registration now uses the Installation ID

An app instance needs an address so you can send to it. The Flutter FCM setup page now marks the old getToken() registration token as deprecated and recommends the Firebase Installation ID (FID). Do not mix the two for the same job.

To use FIDs, turn them on in the app's configuration. On Android add this inside <application> in AndroidManifest.xml:

<meta-data android:name="firebase_messaging_installation_id_enabled"
                         android:value="true" />
              

On iOS add the key FirebaseMessagingInstallationIdEnabled set to true in Info.plist. Then listen first, register second:

final messaging = FirebaseMessaging.instance;
              messaging.onRegistered.listen((String fid) {
                // Send fid to your server, tied to the signed-in user.
              });
              await messaging.register(); // asks for permission if needed
              

The docs say register() asks for notification permission when it has not been granted. On web you pass your VAPID public key to register(). Always subscribe before calling register() so you do not miss the event.

Each platform has one extra step

iOS needs the most setup, because Apple's servers carry the message.

Platform What you must do
iOS Upload an APNs key, enable Push and Background Modes
Android 13 and newer Ask permission at runtime
Web Add a service worker and a VAPID key

The iOS key comes from your Apple developer account. Firebase needs valid APNs credentials, either an authentication key or an APNs certificate, to deliver push notifications to iPhones. The official page walks through the Xcode settings.

Ask for permission at a good moment

requestPermission() returns a NotificationSettings with an authorizationStatus. Do not ask on first launch. Ask after the customer places their first order: "Want a message when it's ready?" Passing provisional: true on Apple platforms asks for provisional permission instead, which lets the user decide later what kind of alerts they want.

Foreground, background and tapped messages are three handlers

The receive messages page separates the cases:

  • FirebaseMessaging.onMessage fires while the app is open. A notification message that arrives then is not shown by default. Show an in-app banner, or explicitly post a local notification on Android using a high-importance notification channel.
  • FirebaseMessaging.onMessageOpenedApp fires when the user taps a notification while the app is in the background.
  • getInitialMessage() returns the message that launched a closed app.

For work when the app is not running, register a background handler. It must not be anonymous, must be top-level, and on Flutter 3.3 or newer needs the pragma:

@pragma('vm:entry-point')
              Future<void> _bgHandler(RemoteMessage message) async {
                await Firebase.initializeApp();
              }
              
              Future<void> main() async {
                WidgetsFlutterBinding.ensureInitialized();
                await Firebase.initializeApp(
                  options: DefaultFirebaseOptions.currentPlatform, // from `flutterfire configure`
                );
                FirebaseMessaging.onBackgroundMessage(_bgHandler);
                runApp(const MyApp());
              }
              

On Android, the background handler runs in a separate isolate; iOS and macOS do not require a separate isolate. Keep background processing independent of UI state. On web, handle background messages in the messaging service worker. Keep it short: the docs warn the OS may kill tasks that run over 30 seconds.

Send a first message

Open the Messaging composer in the Firebase console and target your app. For your own server, use the FCM HTTP v1 API, which authenticates with a server credential. Never put that credential in the app. For "order ready", a Cloud Function can watch the order document and send a push when its status changes.

The default template has no push

The default GrowApps project template does not include firebase_messaging. If an app adds it, the builder's data-safety checklist lists the device registration ID as collected data, so the Google Play Data safety form must declare it. More at growapps.ai.

Send yourself a test push

Send a test message to your own phone from the console while the app is closed, then while it is open. Note which handler fires each time. For notifications the app schedules itself, see flutter_local_notifications.

Sources and further reading