A developer's guide to Firebase Cloud Messaging — from zero to production in under 3 minutes
What is FCM and Why Should You Care?
Firebase Cloud Messaging (FCM) is Google's free service for sending push notifications to Android and iOS devices. The best part? It's completely free — unlimited messages, no credit card required, ever.
Before we dive in, here's why you shouldn't build your own notification system:
| Your DIY Solution | With FCM |
|---|---|
| ❌ Can't deliver when app is closed | ✅ OS handles delivery |
| ❌ Drains battery with persistent connections | ✅ Uses OS push channel |
| ❌ Complex iOS APNs setup | ✅ FCM abstracts it |
| ❌ Need to maintain infrastructure | ✅ Google's global network |
How It Works: The 30-Second Explanation
Your backend never talks directly to users' phones. Instead:
Your Backend → FCM Servers (Google) → User's Device
(sends) (routes) (receives)
FCM uses a device token — a unique string representing one app install on one device — to route messages to the right phone.
The Architecture
Here's what you're building:
┌─────────────────────────────────────────────────────────┐
│ Your Firebase Project │
│ │
│ ┌──────────────────┐ ┌──────────────────────┐ │
│ │ Frontend (App) │ │ Backend (Node.js) │ │
│ │ React Native │ │ Express + Database │ │
│ │ │ │ │ │
│ │ Uses: │ │ Uses: │ │
│ │ • google- │ │ • Service Account │ │
│ │ services.json │ │ JSON (in .env) │ │
│ │ • @react-native- │ │ • firebase-admin │ │
│ │ firebase/ │ │ SDK │ │
│ │ messaging │ │ │ │
│ │ │ │ │ │
│ │ Job: │ │ Job: │ │
│ │ • Get token │ │ • Send push to │ │
│ │ • Request │ │ token via FCM │ │
│ │ permission │ │ API │ │
│ │ • Receive push │ │ │ │
│ └──────────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────────┘
↓ ↓
┌──────────────────────────────┐
│ FCM Servers (Google) │
│ Routes to correct device │
└──────────────────────────────┘
↓
User's Phone
Step 1: Firebase Console Setup (5 minutes)
Create Your Project
- Go to console.firebase.google.com
- Click "Add project"
- Give it a name (e.g.,
my-awesome-app)
Add Android App
- Inside your project → Add app → Android
- Enter your package name (e.g.,
com.myapp) - Download
google-services.json - Place it at
android/app/google-services.jsonin your React Native project
Get Backend Credentials
- Project Settings → Service Accounts
- Click "Generate new private key"
- Downloads a JSON file — this is your admin credential
⚠️ Security Alert: Never commit this file to git. Store it as an environment variable.
Step 2: Backend Setup (Node.js)
Install Firebase Admin SDK
npm install firebase-admin
Initialize Firebase
Create config/firebase.js:
const admin = require('firebase-admin');
const serviceAccount = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
module.exports = admin;
Create Push Notification Service
Create services/pushNotification.js:
const admin = require('../config/firebase');
async function sendPushNotification(deviceToken, title, body, data = {}) {
try {
const message = {
token: deviceToken,
notification: {
title: title,
body: body
},
data: data, // Custom key-value pairs
android: {
priority: 'high' // Wakes up the device
}
};
const response = await admin.messaging().send(message);
console.log('Push sent successfully:', response);
return response;
} catch (error) {
console.error('Error sending push:', error);
// Handle expired/invalid tokens
if (error.code === 'messaging/registration-token-not-registered') {
// Remove token from database
console.log('Token is invalid, should be removed from DB');
}
throw error;
}
}
module.exports = { sendPushNotification };
Environment Variables
Create/update your .env:
# Paste the entire service account JSON as a single-line string
FIREBASE_SERVICE_ACCOUNT={"type":"service_account","project_id":"your-project-id",...}
Step 3: Database Setup
Add a column to store device tokens:
-- For PostgreSQL
ALTER TABLE users ADD COLUMN fcm_token TEXT;
-- For MySQL
ALTER TABLE users ADD COLUMN fcm_token VARCHAR(255);
Important: If you need multi-device support (same user, multiple phones), create a separate table:
CREATE TABLE device_tokens (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
fcm_token TEXT NOT NULL,
device_name VARCHAR(100),
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(user_id, fcm_token)
);
Step 4: API Endpoint to Save Token
Create an endpoint to receive tokens from your app:
// routes/user.js
const express = require('express');
const router = express.Router();
// Assuming you have authentication middleware
router.put('/token', authenticateUser, async (req, res) => {
try {
const { fcm_token } = req.body;
const userId = req.user.id; // From auth middleware
// Update user's FCM token
await db.query(
'UPDATE users SET fcm_token = $1 WHERE id = $2',
[fcm_token, userId]
);
res.json({ success: true, message: 'Token saved successfully' });
} catch (error) {
console.error('Error saving FCM token:', error);
res.status(500).json({ error: 'Failed to save token' });
}
});
module.exports = router;
Understanding Device Tokens
A device token looks like this:
eExKj8mTR4pQ:APA91bH...very-long-alphanumeric-string
Key Facts:
- Unique per device + per app install
- Changes when: app is reinstalled, device is reset, app data is cleared
- Same device, same app, but reinstalled = new token
Token Lifecycle
| Event | Token Changes? |
|---|---|
| App update | ❌ No |
| App uninstall + reinstall | ✅ Yes |
| User clears app data | ✅ Yes |
| Device factory reset | ✅ Yes |
| User switches phones | ✅ Yes (new device) |
The Complete Flow Diagram
Here's how everything connects:
┌─────────────────────────────────────────────────────────────┐
│ REGISTRATION FLOW │
└─────────────────────────────────────────────────────────────┘
[User's Phone] [Your Backend] [Database]
│ │ │
│─── App opens ────────────►│ │
│ Firebase SDK runs │ │
│ Generates token │ │
│ │ │
│─── Login/Signup ─────────►│ │
│ │ │
│─── Send FCM token ───────►│ │
│ PUT /api/user/token │ │
│ │ │
│ │─── Save token ──────►│
│ │ UPDATE users │
│ │ SET fcm_token │
│ │ │
│◄─── Success response ─────│ │
┌─────────────────────────────────────────────────────────────┐
│ NOTIFICATION FLOW │
└─────────────────────────────────────────────────────────────┘
[Your Backend] [Database] [FCM] [User's Phone]
│ │ │ │
│─── Event occurs ────►│ │ │
│ (new message, │ │ │
│ order update, │ │ │
│ etc.) │ │ │
│ │ │ │
│─── Get user token ──►│ │ │
│ SELECT fcm_token │ │ │
│ │ │ │
│◄─── Return token ────│ │ │
│ │ │ │
│─── Send push ───────────────────────►│ │
│ admin.messaging() │ │
│ .send({ token, │ │
│ title, │ │
│ body }) │ │
│ │ │
│ │─── Route to ────►│
│ │ device │
│ │ │
│ │ │
│ │ [Notification │
│ │ appears on │
│ │ lock screen] │
What's in Part 2?
In the next article, we'll cover:
✅ Frontend implementation — Getting the token in React Native
✅ Handling notifications — When app is open, background, or closed
✅ Token refresh logic — Keeping tokens up-to-date
✅ Testing strategies — How to test notifications locally
✅ Production checklist — Everything you need before going live
Quick Reference: Is FCM Really Free?
| Service | Cost |
|---|---|
| FCM push notifications | ✅ Free (unlimited) |
| Firebase project (Spark plan) | ✅ Free |
| Firebase Admin SDK | ✅ Free |
| React Native Firebase package | ✅ Free (open source) |
| Your server hosting | 💰 You pay for hosting |
| Your database | 💰 You pay for database |
FCM has been free since Google acquired Firebase in 2014. No message limits, ever.
Common Mistakes to Avoid
❌ Committing service account JSON to Git
Fix: Add to .gitignore, use environment variables
❌ Not handling token expiration
Fix: Catch messaging/registration-token-not-registered errors and remove stale tokens
❌ Forgetting permission requests
Fix: Always request notification permission on Android 13+ and iOS
❌ Testing only with app open
Fix: Test all three states: foreground, background, and killed
Ready to Implement?
You now have:
- Firebase project configured
- Backend initialized with admin SDK
- Database ready to store tokens
- API endpoint to receive tokens
Next step: Part 2 will show you the React Native frontend code to complete the integration.
Series Navigation:
- Part 1: Concepts & Setup (you are here)
- Part 2: Frontend Implementation & Testing (coming soon)
Found this helpful?
Follow me for Part 2, where we'll implement the complete React Native frontend and handle all notification scenarios.
Tags: #react-native #nodejs #fcm #push-notifications #firebase #mobile-development
Top comments (0)