Back to blog

Flame Blog

How to manually publish messages to the Pub/Sub emulator

Calling the Pub/Sub emulator directly via the HTTP API.

Published April 24, 2026

By Val

When you have Pub/Sub functions defined, a matching topic is automatically provisioned in the emulator.

export const pubsubFunction = functions.pubsub.onMessagePublished(
  { topic: 'my-topic' },
  event => {
    console.log({ event, json: event.data.message.json })
  }
)
export const pubsubFunction = functions.pubsub
  .topic('my-topic')
  .onPublish(message => {
    console.log({ message, json: message.json })
  })

The Pub/Sub emulator runs by default on port 8085 and you can publish messages to it using the Pub/Sub SDK in your favorite language, i.e.:

import { PubSub } from '@google-cloud/pubsub'

const pubsub = new PubSub({
  projectId: 'my-project',
  apiEndpoint: 'localhost:8085',
})

// Can also use an empty constructor with `GOOGLE_CLOUD_PROJECT`
// and `PUBSUB_EMULATOR_HOST` environment variables set.
// const pubsub = new PubSub()

const topic = pubsub.topic('my-topic')

await topic.publishMessage({
  json: {
    foo: 'bar',
  },
})

But in this post I want to go deeper into the weeds and show how to use the emulator’s HTTP API directly.

Publishing a message

To publish a message to a topic, use the :publish endpoint:

curl -X POST 'http://127.0.0.1:8085/v1/projects/my-project/topics/my-topic:publish' \
  -H 'Content-Type: application/json' \
  -d '{"messages": [{"data": "eyJmb28iOiJiYXIifQ=="}]}'

The data field inside each message must be Base64-encoded. Here, the payload is {"foo": "bar"}.

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

To deal with Base64-encoding in the same command, we can do the following:

curl -X POST 'http://127.0.0.1:8085/v1/projects/my-project/topics/my-topic:publish' \
  -H 'Content-Type: application/json' \
  -d '{"messages": [{"data": "'$(echo '{"foo": "bar"}' | base64)'"}]}'

You can also include message attributes:

curl -X POST "http://127.0.0.1:8085/v1/projects/my-project/topics/my-topic:publish" \
  -H "Content-Type: application/json" \
  -d '{
  "messages": [
    {
      "data": "eyJmb28iOiJiYXIifQ==",
      "attributes": {
        "foo": "bar"
      }
    }
  ]
}'

The endpoint will return the message IDs of the published messages:

{
  "messageIds": ["1"]
}

Calling the underlying function directly

If you want to bypass the Pub/Sub emulator entirely and directly call the function behind the topic, check out our dedicated guide to calling Firebase emulator functions.

Stop guessing with Flame ✨

Maybe you don’t want to bother with cURL commands and Base64-encoding when debugging your Pub/Sub functions.

This is why we built Flame, a Firebase emulator UI with everything that’s missing from localhost:4000.

See all your Pub/Sub topics and task queues at a glance, compose messages with a friendly UI, and publish directly to the emulator. No Base64-encoding required.

Flame Pub/Sub topics and message composition

Flame gives you the Pub/Sub UI that’s missing from localhost:4000, and also comes with an improved UI for Firebase Auth, Firestore, Functions, and more.

If that sounds exciting to you, give Flame a try!