Skip to main content
RapidDev - Software Development Agency
firebase-tutorial

How to Schedule Background Functions in Firebase

Schedule background functions in Firebase using Cloud Functions v2 with the onSchedule() trigger and a cron expression. The function runs automatically at the specified interval using Google Cloud Scheduler. Common use cases include nightly data cleanup, daily email digests, periodic API syncs, and usage report generation. Scheduled functions require the Blaze pay-as-you-go plan because Cloud Scheduler is a paid Google Cloud service.

What you'll learn

  • How to create a scheduled function with onSchedule() in Cloud Functions v2
  • How to write cron expressions for common scheduling patterns
  • How to handle timezones and long-running scheduled tasks
  • How to monitor and debug scheduled function executions
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate8 min read15-20 minFirebase Cloud Functions v2, Blaze plan required, Node.js 18/20/22March 2026RapidDev Engineering Team
TL;DR

Schedule background functions in Firebase using Cloud Functions v2 with the onSchedule() trigger and a cron expression. The function runs automatically at the specified interval using Google Cloud Scheduler. Common use cases include nightly data cleanup, daily email digests, periodic API syncs, and usage report generation. Scheduled functions require the Blaze pay-as-you-go plan because Cloud Scheduler is a paid Google Cloud service.

Scheduling Background Functions in Firebase

Firebase Cloud Functions v2 lets you schedule functions to run at regular intervals using cron expressions. Under the hood, Firebase creates a Google Cloud Scheduler job that triggers your function via Pub/Sub. This tutorial covers creating scheduled functions, writing cron expressions, handling timezones, managing long-running tasks, and monitoring executions in production.

Prerequisites

  • A Firebase project on the Blaze pay-as-you-go plan
  • Firebase CLI installed and logged in
  • Cloud Functions initialized in your project (firebase init functions)
  • Node.js 18, 20, or 22 installed locally

Step-by-step guide

1

Create a basic scheduled function with onSchedule()

Import onSchedule from firebase-functions/v2/scheduler and define your function. The first argument is the schedule configuration including the cron expression. The second argument is the async handler function. The handler receives a ScheduledEvent object with the schedule time. Deploy with firebase deploy --only functions and Firebase automatically creates the Cloud Scheduler job.

typescript
1import { onSchedule } from 'firebase-functions/v2/scheduler'
2import { logger } from 'firebase-functions'
3
4// Run every day at midnight UTC
5export const dailyCleanup = onSchedule('every day 00:00', async (event) => {
6 logger.info('Running daily cleanup', { scheduledTime: event.scheduleTime })
7
8 // Your cleanup logic here
9 await deleteExpiredSessions()
10 await archiveOldRecords()
11
12 logger.info('Daily cleanup completed')
13})

Expected result: After deploying, the function runs automatically every day at midnight UTC. You can see executions in the Cloud Functions logs.

2

Write cron expressions for common schedules

Cron expressions have five fields: minute, hour, day-of-month, month, and day-of-week. Firebase also supports the more readable App Engine format. Here are common scheduling patterns you can use directly in your onSchedule() definition.

typescript
1import { onSchedule } from 'firebase-functions/v2/scheduler'
2
3// Every 5 minutes
4export const frequentCheck = onSchedule('*/5 * * * *', async () => {
5 // Runs at :00, :05, :10, :15, etc.
6})
7
8// Every hour at minute 30
9export const hourlySync = onSchedule('30 * * * *', async () => {
10 // Runs at 0:30, 1:30, 2:30, etc.
11})
12
13// Every Monday at 9:00 AM
14export const weeklyReport = onSchedule('0 9 * * 1', async () => {
15 // 1 = Monday
16})
17
18// First day of every month at 6:00 AM
19export const monthlyBilling = onSchedule('0 6 1 * *', async () => {
20 // Day 1 of each month
21})
22
23// App Engine format alternatives
24export const everyHour = onSchedule('every 1 hours', async () => {})
25export const every15Min = onSchedule('every 15 minutes', async () => {})

Expected result: Each function runs at its specified interval. Cloud Scheduler manages the timing automatically.

3

Configure timezone and function options

By default, scheduled functions use UTC. Pass a configuration object instead of a string to set the timezone, memory, timeout, and retry behavior. Use the IANA timezone identifier (like 'America/New_York') to schedule functions in a specific timezone. Set timeoutSeconds for functions that need more than the default 60 seconds.

typescript
1import { onSchedule } from 'firebase-functions/v2/scheduler'
2
3export const morningDigest = onSchedule(
4 {
5 schedule: 'every day 08:00',
6 timeZone: 'America/New_York',
7 timeoutSeconds: 300, // 5 minutes
8 memory: '512MiB',
9 retryCount: 3
10 },
11 async (event) => {
12 // Runs at 8:00 AM Eastern Time every day
13 // Automatically handles EST/EDT transitions
14 await sendDailyDigestEmails()
15 }
16)

Expected result: The function runs at 8:00 AM Eastern Time regardless of DST changes. Failed executions are retried up to 3 times.

4

Interact with Firestore from a scheduled function

Scheduled functions commonly perform database maintenance tasks. Use the Firebase Admin SDK to access Firestore without security rule restrictions. The Admin SDK is automatically initialized in Cloud Functions — just import it and use it. Common patterns include deleting expired documents, aggregating daily stats, and archiving old data.

typescript
1import { onSchedule } from 'firebase-functions/v2/scheduler'
2import { logger } from 'firebase-functions'
3import { getFirestore, Timestamp } from 'firebase-admin/firestore'
4import { initializeApp } from 'firebase-admin/app'
5
6initializeApp()
7const db = getFirestore()
8
9export const cleanupExpiredSessions = onSchedule(
10 {
11 schedule: 'every 1 hours',
12 timeoutSeconds: 120,
13 memory: '256MiB'
14 },
15 async () => {
16 const now = Timestamp.now()
17 const expiredQuery = db
18 .collection('sessions')
19 .where('expiresAt', '<', now)
20 .limit(500) // Batch to stay within limits
21
22 const snapshot = await expiredQuery.get()
23
24 if (snapshot.empty) {
25 logger.info('No expired sessions to clean up.')
26 return
27 }
28
29 const batch = db.batch()
30 snapshot.docs.forEach((doc) => {
31 batch.delete(doc.ref)
32 })
33
34 await batch.commit()
35 logger.info(`Deleted ${snapshot.size} expired sessions.`)
36 }
37)

Expected result: Every hour, the function checks for expired sessions and deletes them in batches, logging the number of documents removed.

5

Deploy and monitor scheduled functions

Deploy your scheduled functions with the Firebase CLI. After deployment, Firebase creates the Cloud Scheduler job automatically. Monitor executions in the Firebase Console under Functions > Logs, or in Google Cloud Console under Cloud Scheduler to see job history and next run times. You can also manually trigger a scheduled function from Cloud Scheduler for testing.

typescript
1# Deploy all functions
2firebase deploy --only functions
3
4# Deploy a specific function
5firebase deploy --only functions:dailyCleanup
6
7# View function logs
8firebase functions:log --only dailyCleanup
9
10# List Cloud Scheduler jobs (via gcloud)
11gcloud scheduler jobs list
12
13# Manually trigger for testing
14gcloud scheduler jobs run firebase-schedule-dailyCleanup-us-central1

Expected result: The function is deployed and Cloud Scheduler shows the job with its next run time. Logs confirm successful executions.

Complete working example

scheduled-functions.ts
1import { onSchedule } from 'firebase-functions/v2/scheduler'
2import { logger } from 'firebase-functions'
3import { initializeApp } from 'firebase-admin/app'
4import { getFirestore, Timestamp, FieldValue } from 'firebase-admin/firestore'
5
6initializeApp()
7const db = getFirestore()
8
9// Daily cleanup: delete expired sessions and old notifications
10export const dailyCleanup = onSchedule(
11 {
12 schedule: 'every day 02:00',
13 timeZone: 'UTC',
14 timeoutSeconds: 300,
15 memory: '512MiB',
16 retryCount: 2
17 },
18 async () => {
19 const now = Timestamp.now()
20 let totalDeleted = 0
21
22 // Delete expired sessions in batches
23 let hasMore = true
24 while (hasMore) {
25 const snapshot = await db
26 .collection('sessions')
27 .where('expiresAt', '<', now)
28 .limit(500)
29 .get()
30
31 if (snapshot.empty) {
32 hasMore = false
33 break
34 }
35
36 const batch = db.batch()
37 snapshot.docs.forEach((doc) => batch.delete(doc.ref))
38 await batch.commit()
39 totalDeleted += snapshot.size
40
41 if (snapshot.size < 500) hasMore = false
42 }
43
44 logger.info(`Daily cleanup: deleted ${totalDeleted} expired sessions`)
45 }
46)
47
48// Hourly stats aggregation
49export const hourlyStats = onSchedule(
50 {
51 schedule: '0 * * * *',
52 timeoutSeconds: 120,
53 memory: '256MiB'
54 },
55 async () => {
56 const oneHourAgo = Timestamp.fromMillis(Date.now() - 60 * 60 * 1000)
57
58 const snapshot = await db
59 .collection('events')
60 .where('createdAt', '>', oneHourAgo)
61 .get()
62
63 const today = new Date().toISOString().split('T')[0]
64 await db.doc(`stats/${today}`).set(
65 {
66 hourlyEvents: FieldValue.increment(snapshot.size),
67 lastUpdated: Timestamp.now()
68 },
69 { merge: true }
70 )
71
72 logger.info(`Hourly stats: ${snapshot.size} events in the last hour`)
73 }
74)

Common mistakes when scheduling Background Functions in Firebase

Why it's a problem: Trying to deploy scheduled functions on the Spark free plan, which does not support Cloud Scheduler

How to avoid: Upgrade to the Blaze pay-as-you-go plan. Cloud Scheduler and Cloud Functions are Blaze-only services. Cloud Scheduler costs $0.10 per job per month.

Why it's a problem: Not handling the case where a scheduled function takes longer than the default 60-second timeout

How to avoid: Set timeoutSeconds in the function options. V2 scheduled functions support up to 1800 seconds (30 minutes). For longer tasks, break the work into smaller batches.

Why it's a problem: Creating infinite loops by writing to a collection that triggers another Cloud Function, which writes back

How to avoid: Use conditional checks in Firestore triggers to prevent re-processing. For scheduled functions, write to a separate output collection or use a processed flag to avoid loops.

Why it's a problem: Assuming the function runs at the exact scheduled second — Cloud Scheduler has a delivery tolerance

How to avoid: Cloud Scheduler guarantees at-least-once delivery but may trigger slightly late (usually within a few seconds). Do not rely on exact-second timing. Use the event.scheduleTime property for the intended execution time.

Best practices

  • Always set a timezone explicitly for user-facing schedules to avoid confusion with UTC and daylight saving time
  • Set appropriate timeoutSeconds based on the expected duration of your task — do not rely on the default
  • Use batched operations when processing large datasets to stay within Firestore's 500-operation batch limit
  • Log the start and completion of scheduled tasks for monitoring and debugging
  • Set retryCount to at least 2 for critical tasks like billing or email sends to handle transient failures
  • Use gcloud scheduler jobs run to test scheduled functions manually during development
  • Keep scheduled functions idempotent — they should produce the same result if run twice with the same data
  • Monitor Cloud Scheduler job history in Google Cloud Console to catch silent failures

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I need to create several scheduled Firebase Cloud Functions v2: a daily cleanup that deletes expired Firestore documents, an hourly stats aggregator, and a weekly email digest. Show me how to write these using onSchedule with cron expressions, timezone configuration, proper timeout settings, and Firestore Admin SDK operations including batched deletes.

Firebase Prompt

Create a Firebase Cloud Functions v2 scheduled function that runs every night at 2 AM Eastern Time. It should query a Firestore 'sessions' collection for documents where expiresAt is in the past, delete them in batches of 500, and log the total count deleted. Include timezone configuration, error handling, timeout settings, and retry configuration.

Frequently asked questions

Do scheduled functions require the Blaze plan?

Yes. Cloud Scheduler is a paid Google Cloud service, and Cloud Functions require the Blaze plan. Cloud Scheduler costs $0.10 per job per month. The Blaze plan includes a generous free tier for Cloud Functions (2 million invocations per month).

What is the maximum timeout for a scheduled function?

V2 scheduled functions support a maximum timeout of 1800 seconds (30 minutes). V1 functions are limited to 540 seconds (9 minutes). If your task needs more than 30 minutes, break it into smaller sub-tasks triggered in sequence.

How do I test a scheduled function without waiting for the schedule?

Use the Firebase Emulator Suite for local testing. For deployed functions, use gcloud scheduler jobs run followed by the job name to trigger the function manually. The job name follows the pattern firebase-schedule-functionName-region.

Can I schedule a function to run every second or every 10 seconds?

No. The minimum interval for Cloud Scheduler is 1 minute. For sub-minute intervals, consider using a Pub/Sub-triggered function with a Cloud Tasks queue, or run a persistent process on a reserved VM.

What happens if a scheduled function fails?

Cloud Scheduler retries the delivery based on your retryCount setting. The default is 0 retries. Set retryCount in the function options to enable automatic retries. Each retry is a separate function invocation.

Can RapidDev help me set up scheduled background tasks in Firebase?

Yes. RapidDev can design and implement scheduled Cloud Functions for data cleanup, report generation, API synchronization, and other recurring tasks, including monitoring and error handling.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.