Testing apps locally with the emulator

To develop and test your application locally, you can use the Pub/Subemulator, which provideslocal emulationof the production Pub/Sub service. You run the Pub/Subemulator using the Google Cloud CLI.

To run your application against the emulator, first start theemulator and set the environment variables. Your application must communicatewith the emulator instead of the production Pub/Sub service. Theresources created and messages published to the emulator are maintained for thelifetime of the emulator session.

Note: To test push subscriptions in the emulator,you can use unencrypted push endpoints (that is,http), as in thefollowing examples. In production, only secure push endpoints (https)are allowed.

Before you begin

Complete the following prerequisites before you use the Pub/Subemulator:

Install the emulator

Install the emulator from a command prompt:

gcloud components install pubsub-emulatorgcloud components update

Install the emulator as a container image

To install and run the emulator as a container, download and install thegCloud Docker image.

Starting the emulator

Start the emulator by invokingpubsub start from a command prompt. Beforerunning the command, replacePUBSUB_PROJECT_ID with a validGoogle Cloudproject ID.string. The string doesn't need torepresent a real Google Cloud project because thePub/Sub emulator runs locally.

gcloud beta emulators pubsub start --project=PUBSUB_PROJECT_ID [options]

Seegcloud beta emulators pubsub startfor a complete list of flags.

After you start the emulator, you see a message that resembles the following:

...[pubsub] This is the Pub/Sub fake.[pubsub] Implementation may be incomplete or differ from the real system....[pubsub] INFO: Server started, listening on 8085

This message indicates that the Pub/Sub server runs at the emulator endpointon your local machine instead of the Google Cloud endpoint. All operationshappen locally, including the following:

  • Creating a topic or subscription
  • Publishing
  • Subscribing
Note: The emulator listens on port 8085 on your IPv6 localhost (::1) by default. You can have the emulator listen on port 8085 on all IP addresses on your system by setting--host-port=0.0.0.0:8085. If you have IPv6 disabled on your system, you can specify IPv4 (127.0.0.1) by setting--host-port=127.0.0.1:8085.

Setting environment variables

After you start the emulator, you must set the environment variables so that yourapplication connects to the emulator instead of Pub/Sub. Setthese environment variables on the same machine that you use to run your application.

You must set the environment variables each time you start the emulator. Theenvironment variables depend on dynamically assigned port numbers that couldchange when you restart the emulator.

Automatically setting the variables

If your application and the emulator run on the same machine, you can set theenvironment variables automatically:

Linux / macOS

Runenv-init using command substitution:

$(gcloud beta emulators pubsub env-init)

Windows

Create and run a batch file using output fromenv-init:

gcloud beta emulators pubsub env-init > set_vars.cmd && set_vars.cmd

Your application will now connect to the Pub/Sub emulator.

Manually setting the variables

If your application and the emulator run on different machines, set theenvironment variables manually:

  1. Run theenv-init command:

     gcloud beta emulators pubsub env-init

  2. On the machine that runs your application, set thePUBSUB_EMULATOR_HOSTenvironment variable and value as directed by the output of theenv-initcommand. This configuration connects you application to the emulator.You can optionally set thePUBSUB_PROJECT_ID environmentvariable for the project that you want to use for the emulator.

    Linux / macOS
    export PUBSUB_EMULATOR_HOST=[::1]:8432export PUBSUB_PROJECT_ID=my-project-id
    Windows
    set PUBSUB_EMULATOR_HOST=[::1]:8432set PUBSUB_PROJECT_ID=my-project-id

Your application will now connect to the Pub/Sub emulator.

Note: If you're using the Python App Engine Standardlocaldevelopment server,you must pass this environment variable on the command line as follows:

dev_appserver.pyapp.yaml--env_varPUBSUB_EMULATOR_HOST=${PUBSUB_EMULATOR_HOST}

dev_appserver.py is included in your[PATH_TO_CLOUD_SDK]/google-cloud-sdk/bin/dev_appserver.py.

Using the emulator

To use the emulator, you must have an application built using theCloud Client Libraries.The emulator does not support Google Cloud console orgcloud pubsubcommands.

The following example demonstrates using the emulator and an applicationthat uses thePython Cloud Client Libraryto perform various operations. Examples of these operations include how tocreate a topic, publish messages, and read messages.

Complete the following steps on the machine where you set theemulatorenvironment variables:

  1. Get the Pub/Sub Python samples from GitHubbycloning the full Python repository.

  2. In your cloned repository, navigate to thesamples/snippets directory.You complete the rest of these steps in this directory.

  3. From within thesamples/snippets directory, install the dependencies you need to run the example:

    pip install -r requirements.txt
  4. Create a topic:

     python publisher.pyPUBSUB_PROJECT_ID createTOPIC_ID
  5. (Optional) If you don't have a local push endpointfor testing push subscriptions in the emulator, complete the following stepsto create one onhttp://[::1]:3000/messages.

    1. InstallJSON Server.
      npm install -g json-server
    2. Start JSON Server.
      json-server --port 3000 --watch db.json
      wheredb.json contains the following starter code:
      {   "messages": []}
    3. Note downhttp://[::1]:3000/messages forPUSH_ENDPOINT in the next step.
  6. Create a subscription to the topic:

    • Create a pull subscription:

      python subscriber.pyPUBSUB_PROJECT_ID createTOPIC_IDSUBSCRIPTION_ID
    • Create a push subscription:

      python subscriber.pyPUBSUB_PROJECT_ID create-pushTOPIC_IDSUBSCRIPTION_ID \PUSH_ENDPOINT
  7. Publish messages to the topic:

     python publisher.pyPUBSUB_PROJECT_ID publishTOPIC_ID
  8. Read the messages published to the topic:

    • Retrieve messages from your pull subscription:

      python subscriber.pyPUBSUB_PROJECT_ID receiveSUBSCRIPTION_ID
    • Observe the messages delivered to your local push endpoint. For example, messages look like the following:

      {  "messages": [      {          "subscription": "projects/PUBSUB_PROJECT_ID/subscriptions/SUBSCRIPTION_ID",          "message": {              "data": "TWVzc2FnZSBudW1iZXIgMQ==",              "messageId": "10",              "attributes": {}          },          "id": 1      },      ...  ]}

Accessing environment variables

In all languages except for Java and C#, if you have setPUBSUB_EMULATOR_HOSTas described inSetting environment variables,the Pub/Sub client libraries automatically call the API running in thelocal instance rather than Pub/Sub.

However, C# and Java client libraries require you to modify your code to use theemulator:

C#

Before trying this sample, follow theC# setup instructions in thePub/Sub quickstart using client libraries. For more information, see thePub/SubC# API reference documentation.

To authenticate to Pub/Sub, set up Application Default Credentials. For more information, seeSet up authentication for a local development environment.

usingGoogle.Api.Gax;usingGoogle.Cloud.PubSub.V1;usingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;publicclassEmulatorSupportSample{publicasyncTaskWithEmulatorAsync(stringprojectId,stringtopicId,stringsubscriptionId){// Use EmulatorDetection.EmulatorOrProduction to create service clients that will// that will connect to the PubSub emulator if the PUBSUB_EMULATOR_HOST environment// variable is set, but will otherwise connect to the production environment.// Create the PublisherServiceApiClient using the PublisherServiceApiClientBuilder// and setting the EmulatorDection property.PublisherServiceApiClientpublisherService=awaitnewPublisherServiceApiClientBuilder{EmulatorDetection=EmulatorDetection.EmulatorOrProduction}.BuildAsync();// Use the client as you'd normally do, to create a topic in this example.TopicNametopicName=newTopicName(projectId,topicId);publisherService.CreateTopic(topicName);// Create the SubscriberServiceApiClient using the SubscriberServiceApiClientBuilder// and setting the EmulatorDection property.SubscriberServiceApiClientsubscriberService=awaitnewSubscriberServiceApiClientBuilder{EmulatorDetection=EmulatorDetection.EmulatorOrProduction}.BuildAsync();// Use the client as you'd normally do, to create a subscription in this example.SubscriptionNamesubscriptionName=newSubscriptionName(projectId,subscriptionId);subscriberService.CreateSubscription(subscriptionName,topicName,pushConfig:null,ackDeadlineSeconds:60);// Create the PublisherClient using PublisherClientBuilder to set the EmulatorDetection property.PublisherClientpublisher=awaitnewPublisherClientBuilder{TopicName=topicName,EmulatorDetection=EmulatorDetection.EmulatorOrProduction}.BuildAsync();// Use the client as you'd normally do, to send a message in this example.awaitpublisher.PublishAsync("Hello, Pubsub");awaitpublisher.ShutdownAsync(TimeSpan.FromSeconds(15));// Create the SubscriberClient using SubscriberClientBuild to set the EmulatorDetection property.SubscriberClientsubscriber=awaitnewSubscriberClientBuilder{SubscriptionName=subscriptionName,EmulatorDetection=EmulatorDetection.EmulatorOrProduction}.BuildAsync();List<PubsubMessage>receivedMessages=newList<PubsubMessage>();// Use the client as you'd normally do, to listen for messages in this example.awaitsubscriber.StartAsync((msg,cancellationToken)=>{receivedMessages.Add(msg);Console.WriteLine($"Received message {msg.MessageId} published at {msg.PublishTime.ToDateTime()}");Console.WriteLine($"Text: '{msg.Data.ToStringUtf8()}'");// In this example we stop the subscriber when the message is received.// You may leave the subscriber running, and it will continue to received published messages// if any.// This is non-blocking, and the returned Task may be awaited.subscriber.StopAsync(TimeSpan.FromSeconds(15));// Return Reply.Ack to indicate this message has been handled.returnTask.FromResult(SubscriberClient.Reply.Ack);});}}

Java

Before trying this sample, follow theJava setup instructions in thePub/Sub quickstart using client libraries. For more information, see thePub/SubJava API reference documentation.

To authenticate to Pub/Sub, set up Application Default Credentials. For more information, seeSet up authentication for a local development environment.

importcom.google.api.core.ApiFuture;importcom.google.api.gax.core.CredentialsProvider;importcom.google.api.gax.core.NoCredentialsProvider;importcom.google.api.gax.grpc.GrpcTransportChannel;importcom.google.api.gax.rpc.FixedTransportChannelProvider;importcom.google.api.gax.rpc.TransportChannelProvider;importcom.google.cloud.pubsub.v1.Publisher;importcom.google.cloud.pubsub.v1.TopicAdminClient;importcom.google.cloud.pubsub.v1.TopicAdminSettings;importcom.google.protobuf.ByteString;importcom.google.pubsub.v1.PubsubMessage;importcom.google.pubsub.v1.Topic;importcom.google.pubsub.v1.TopicName;importio.grpc.ManagedChannel;importio.grpc.ManagedChannelBuilder;publicclassUsePubSubEmulatorExample{publicstaticvoidmain(String...args)throwsException{Stringhostport=System.getenv("PUBSUB_EMULATOR_HOST");ManagedChannelchannel=ManagedChannelBuilder.forTarget(hostport).usePlaintext().build();try{TransportChannelProviderchannelProvider=FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel));CredentialsProvidercredentialsProvider=NoCredentialsProvider.create();// Set the channel and credentials provider when creating a `TopicAdminClient`.// Can be done similarly for a `SubscriptionAdminClient`.TopicAdminClienttopicAdminClient=TopicAdminClient.create(TopicAdminSettings.newBuilder().setTransportChannelProvider(channelProvider).setCredentialsProvider(credentialsProvider).build());TopicNametopicName=TopicName.of("my-project-id","my-topic-id");Topictopic=topicAdminClient.createTopic(topicName);System.out.println("Created topic: "+topic.getName());// Set the channel and credentials provider when creating a `Publisher`.// Can be done similarly for a `Subscriber`.Publisherpublisher=Publisher.newBuilder(topicName).setChannelProvider(channelProvider).setCredentialsProvider(credentialsProvider).build();Stringmessage="Hello World!";ByteStringdata=ByteString.copyFromUtf8(message);PubsubMessagepubsubMessage=PubsubMessage.newBuilder().setData(data).build();ApiFuture<String>messageIdFuture=publisher.publish(pubsubMessage);StringmessageId=messageIdFuture.get();System.out.println("Published message ID: "+messageId);}finally{channel.shutdown();}}}

Stopping the emulator

To stop the emulator, pressControl+C.

After you stop the emulator, run the following command to removethePUBSUB_EMULATOR_HOST environment variable so your application willconnect to Pub/Sub:

Linux / macOS
unset PUBSUB_EMULATOR_HOST
Windows
set PUBSUB_EMULATOR_HOST=

Emulator command-line arguments

For details on command-line arguments for the Pub/Sub emulator, seegcloud beta emulators pubsub.

Supported features

The emulator supports the following Pub/Sub features:

  • Publishing messages
  • Receiving messages from push and pull subscriptions
  • Ordering messages
  • Replaying messages
  • Forwarding messages to dead-letter topics
  • Retry policies on message delivery
  • Schema support for Avro
  • Filtering

Known limitations

  • UpdateTopic andUpdateSnapshot RPCs are not supported.
  • IAM operations are not supported.
  • Configurable message retention is not supported; all messages are retainedindefinitely.
  • Subscription expiration is not supported. Subscriptions don't expire.
  • Schema support for protocol buffers.
  • BigQuery subscriptions can be created, but don't send messages toBigQuery.
  • Seek to a timestamp for ordered subscriptions is not supported.
  • Topics and subscriptions can be created with Single Message Transforms (SMTs)but messages won't be transformed.

To file issues, submit aPublic issue tracker.

What's next

  • To learn how to use the Pub/Sub emulator with minikube, seethisblog post.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-19 UTC.