Back to blog

Flame Blog

How to manually trigger Cloud Tasks in the emulator

Publishing Cloud Tasks to the emulator via the HTTP API.

Published April 24, 2026

By Val

When you define task queue handlers in your Firebase Functions, a matching task queue is automatically created in the emulator.

export const taskQueueFunction = functions.tasks.onTaskDispatched(
  {
    retryConfig: {
      maxAttempts: 5,
      minBackoffSeconds: 60,
    },
    rateLimits: {
      maxConcurrentDispatches: 6,
    },
  },
  async request => {
    console.log({ data: request.data })
  }
)
export const taskQueueFunction = functions.tasks
  .taskQueue({
    retryConfig: {
      maxAttempts: 5,
      minBackoffSeconds: 60,
    },
    rateLimits: {
      maxConcurrentDispatches: 6,
    },
  })
  .onDispatch(async data => {
    console.log({ data })
  })

The Cloud Tasks emulator runs by default on port 9499 and you can push tasks to it using the SDK:

import { initializeApp } from 'firebase-admin/app'
import { getFunctions } from 'firebase-admin/functions'

// Can also use `GOOGLE_CLOUD_PROJECT` environment variable
initializeApp({ projectId: 'my-project' })

process.env.CLOUD_TASKS_EMULATOR_HOST = 'localhost:9499'

const queue = getFunctions().taskQueue('taskQueueFunction')

await queue.enqueue(data)

But in this post I want to get into the details and show how to create tasks directly using the emulator’s HTTP API.

Creating a task

To push a task onto a queue manually, POST to the emulator’s tasks endpoint:

curl -X POST 'http://localhost:9499/projects/my-project/locations/us-central1/queues/taskQueueFunction/tasks' \
  -H 'Content-Type: application/json' \
  -d '{
  "task": {
    "httpRequest": {
      "httpMethod": "POST",
      "url": "http://localhost:5001/my-project/us-central1/taskQueueFunction",
      "body": "eyJkYXRhIjp7ImZvbyI6ImJhciJ9fQ==",
      "headers": {
        "Content-Type": "application/json"
      }
    }
  }
}'

The queue is not directly linked to the function, so we need to be explicit about the URL to the functions emulator to dispatch the task to.

The body field inside httpRequest is Base64-encoded and the actual payload needs to be inside a data field. In this example we’re passing {"data": {"foo": "bar"}}.

Buffer.from(JSON.stringify({ data: { foo: 'bar' } })).toString('base64')
// 'eyJkYXRhIjp7ImZvbyI6ImJhciJ9fQ=='

We can inline the Base64 encoding in the command for convenience:

curl -X POST 'http://localhost:9499/projects/my-project/locations/us-central1/queues/taskQueueFunction/tasks' \
  -H 'Content-Type: application/json' \
  -d '{
  "task": {
    "httpRequest": {
      "httpMethod": "POST",
      "url": "http://localhost:5001/my-project/us-central1/taskQueueFunction",
      "body": "'$(echo '{"data": {"foo": "bar"}}' | base64)'",
      "headers": {
        "Content-Type": "application/json"
      }
    }
  }
}'

The emulator will then dispatch the task to your function just as it would in production, with retries and all.

Calling the function directly

Since the Task Queue emulator just forwards the HTTP request to the functions emulator, you can also call the function directly. In the above example that would be (from our guide to calling Firebase emulator functions):

curl -X POST 'http://localhost:5001/my-project/us-central1/taskQueueFunction' \
  -H 'Content-Type: application/json' \
  -d '{"data": {"foo": "bar"}}'

You won’t get the retry behavior but it’s faster and you don’t need the Cloud Tasks API overhead.

Flame: the missing UI for the emulator ✨

Did you ever wish that localhost:4000 had an admin for the emulator queues and functions?

This is why we built Flame, a Firebase emulator UI with everything that’s missing from the built-in admin.

No more guesswork with cURL commands, JSON protocols and Base64-encoding when debugging your queues, tasks and Firebase Functions. Just input your payload and send.

Flame task queue message composition

Also comes with an improved UI for Firebase Auth, Firestore, and more. Try it out!