A Pub/Sub emulator, without Java

Run the Pub/Sub emulator on its own with one npm command: every RPC of the official emulator over gRPC and HTTP/JSON on port 8085, push delivery, and a console to see your messages. No Java, no gcloud.

npx firenook emulators:start --only pubsub
Read the Pub/Sub docs
publish.mjs@google-cloud/pubsub
import { PubSub } from '@google-cloud/pubsub';

const pubsub = new PubSub({ projectId: 'demo-shop' });
const [topic] = await pubsub.createTopic('orders');
const [subscription] = await topic.createSubscription('receipts');

subscription.on('message', (message) => {
  console.log('received', message.data.toString(), message.attributes);
  message.ack();
});

await topic.publishMessage({
  json: { order: 'o-1001', total: 36 },
  attributes: { source: 'checkout' },
});
Terminal
            
            
                $ npx firenook emulators:start --only pubsub
              
          
            

            
                $ PUBSUB_EMULATOR_HOST=127.0.0.1:8085 node publish.mjs
              
          
            

            received {"order":"o-1001","total":36} { source: 'checkout' }
          

The whole emulator, checked against the official one

Firenook answers every request the way the official Pub/Sub emulator does, step by step, so your client libraries and tests get what they expect.

  • Every RPC of the official emulator

    Publisher, Subscriber, SchemaService and IAMPolicy, over gRPC and HTTP/JSON on one port, replayed from a 916-step record of the official emulator’s answers.

  • Delivery as production does it

    Pull, streaming pull and push with retries, ack deadlines and redelivery, ordering keys, filters, and dead-letter and retry policies.

  • Seek, snapshots and schemas

    Message retention, seek to a time or a snapshot, and Avro schemas with revisions, bound to topics.

  • Your functions on the topics

    onMessagePublished functions receive what you publish, dead-lettered messages included, and scheduled functions run in their own time zone.

  • A console for the messages

    Each topic’s history, a subscription’s backlog without taking it, publishing, and acknowledging or releasing a message by hand.

  • One npm package

    No Java and no gcloud. The emulator is native code in the package you install with npm or Bun, on macOS, Linux and Windows.

Like the official emulator, it keeps nothing across restarts. What Pub/Sub covers in 0.2.0.

On its own, or with your functions

Use it alone for a service that only needs Pub/Sub, or start the whole suite and your functions get every message published to their topics.

Scheduled functions publish to their own topics on schedule, in their time zone, and the console can run one now. Pub/Sub listens on 8085 unless firebase.json says otherwise.

functions/index.jsfirebase-functions
const { onMessagePublished } = require('firebase-functions/pubsub');

exports.sendReceipt = onMessagePublished('orders', (event) => {
  const order = event.data.message.json;
  console.log('receipt for', order.order, 'total', order.total);
});

Questions

The rest is in the Pub/Sub docs. Something else? Ask on GitHub.

Does it need Java or gcloud?

No. The official Pub/Sub emulator comes with the Google Cloud CLI and runs on Java. Firenook’s is native code in one npm package, on macOS, Linux and Windows.

Which client libraries work with it?

Any that read PUBSUB_EMULATOR_HOST, as Google’s client libraries do: set it to 127.0.0.1:8085, or the port firebase.json gives Pub/Sub, and they connect without credentials.

Do I need a firebase.json?

Yes, as with the Firebase CLI, but the smallest one will do: {"emulators": {"pubsub": {"port": 8085}}}. Without a .firebaserc, add --project demo-yourapp.

Are messages kept after a restart?

No, as with the official emulator: topics, subscriptions and messages start empty each time. --keep-data keeps Firestore, Auth and Storage.

What does it not do?

Protocol Buffer schemas, IAM, detachSubscription and updateSnapshot (the official emulator answers 501 too), and BigQuery, Cloud Storage and Bigtable export subscriptions.

Where does it differ from the official emulator?

In three places, each following production: an acknowledged message is dropped once nothing can bring it back, a topic’s history is a bounded ring, and dead-lettered messages reach the functions on the dead-letter topic.

Start Pub/Sub in one command

Install Firenook in your project and give firebase.json a Pub/Sub entry. It is ready on its port in under a second.

npx firenook emulators:start --only pubsub
Install Firenook