To develop and test your application locally, you can use the Pub/Sub
emulator, which provides [local emulation](https://docs.cloud.google.com/sdk/gcloud/reference/beta/emulators)
of the production Pub/Sub service. You run the Pub/Sub
emulator using the Google Cloud CLI.

To run your application against the emulator, first start the
emulator and set the environment variables. Your application must communicate
with the emulator instead of the production Pub/Sub service. The
resources created and messages published to the emulator are maintained for the
lifetime of the emulator session.

> [!NOTE]
> **Note:** To test push subscriptions in the emulator, you can use unencrypted push endpoints (that is, `http`), as in the following examples. In production, only secure push endpoints (`https`) are allowed.

## Before you begin

Complete the following prerequisites before you use the Pub/Sub
emulator:

- Set up a [Python development environment](https://docs.cloud.google.com/python/docs/setup.md.txt).

- Install a [JDK](https://docs.cloud.google.com/java/docs/setup.md.txt#install_a_jdk_java_development_kit).

- Install [Google Cloud CLI](https://docs.cloud.google.com/sdk/docs/install).

- Build an application by using the [Cloud Client Libraries](https://docs.cloud.google.com/pubsub/docs/reference/libraries.md.txt#gcloud-libraries).

## Install the emulator

Install the emulator from a command prompt:

```sh
gcloud components install pubsub-emulator
gcloud components update
```

### Install the emulator as a container image

To install and run the emulator as a container, download and install the
[Google Cloud CLI Docker image](https://docs.cloud.google.com/sdk/docs/downloads-docker.md.txt).

## Starting the emulator

Start the emulator by invoking `pubsub start` from a command prompt. Before
running the command, replace <var translate="no">PUBSUB_PROJECT_ID</var> with a valid
Google Cloud [project ID](https://docs.cloud.google.com/resource-manager/reference/rest/v1/projects.md.txt#Project)
string. The string doesn't need to
represent a real Google Cloud project because the
Pub/Sub emulator runs locally.

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

See [`gcloud beta emulators pubsub start`](https://docs.cloud.google.com/sdk/gcloud/reference/beta/emulators/pubsub/start)
for a complete list of flags.

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

```sh
...
[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 endpoint
on your local machine instead of the Google Cloud endpoint. All operations
happen locally, including the following:

- Creating a topic or subscription
- Publishing
- Subscribing

> [!NOTE]
> **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 <var translate="no">--host-port=0.0.0.0:8085</var>. If you have IPv6 disabled on your system, you can specify IPv4 (127.0.0.1) by setting <var translate="no">--host-port=127.0.0.1:8085</var>.

## Setting environment variables

After you start the emulator, you must set the environment variables so that your
application connects to the emulator instead of Pub/Sub. Set
these 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. The
environment variables depend on dynamically assigned port numbers that could
change when you restart the emulator.

### Automatically setting the variables

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

### Linux / macOS

Run `env-init` using command substitution:

```sh
$(gcloud beta emulators pubsub env-init)
```

### Windows

Create and run a batch file using output from `env-init`:

```sh
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 the
environment variables manually:

1. Run the `env-init` command:

   <br />

   ```
    gcloud beta emulators pubsub env-init
   ```

   <br />

2. On the machine that runs your application, set the `PUBSUB_EMULATOR_HOST`
   environment variable and value as directed by the output of the `env-init`
   command. This configuration connects you application to the emulator.
   You can optionally set the `PUBSUB_PROJECT_ID` environment
   variable for the project that you want to use for the emulator.

   Linux / macOS

   ```
   export PUBSUB_EMULATOR_HOST=[::1]:8432
   export PUBSUB_PROJECT_ID=my-project-id
   ```
   Windows

   ```
   set PUBSUB_EMULATOR_HOST=[::1]:8432
   set 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 Standard [local
development server](https://docs.cloud.google.com/appengine/docs/standard/python/tools/using-local-server),
you must pass this environment variable on the command line as follows:

```bash
dev_appserver.py app.yaml --env_var PUBSUB_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 the [Cloud Client Libraries](https://docs.cloud.google.com/pubsub/libraries#gcloud-libraries).
The emulator does not support Google Cloud console or [`gcloud pubsub`](https://docs.cloud.google.com/sdk/gcloud/reference/pubsub)
commands.

The following example demonstrates using the emulator and an application
that uses the
[Python Cloud Client Library](https://docs.cloud.google.com/pubsub/docs/reference/libraries.md.txt#client-libraries-install-python)
to perform various operations. Examples of these operations include how to
create a topic, publish messages, and read messages.

Complete the following steps on the machine where you set the [emulator
environment variables](https://docs.cloud.google.com/pubsub/docs/emulator#env):

1. Get the Pub/Sub Python samples from GitHub
   by [cloning the full Python repository](https://github.com/googleapis/python-pubsub).

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

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

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

   ```sh
    python publisher.py PUBSUB_PROJECT_ID create TOPIC_ID
   ```
5. (Optional) If you don't have a local push endpoint
   for testing push subscriptions in the emulator, complete the following steps
   to create one on `http://[::1]:3000/messages`.

   1. Install [JSON Server](https://www.npmjs.com/package/json-server).

      ```sh
      npm install -g json-server
      ```
   2. Start JSON Server.

      ```sh
      json-server --port 3000 --watch db.json
      ```
      where `db.json` contains the following starter code:

      ```sh
      {
         "messages": []
      }
      ```
   3. Note down `http://[::1]:3000/messages` for <var translate="no">PUSH_ENDPOINT</var> in the next step.
6. Create a subscription to the topic:

   - Create a pull subscription:

     ```sh
     python subscriber.py PUBSUB_PROJECT_ID create TOPIC_ID SUBSCRIPTION_ID
     ```
   - Create a push subscription:

     ```sh
     python subscriber.py PUBSUB_PROJECT_ID create-push TOPIC_ID SUBSCRIPTION_ID \
     PUSH_ENDPOINT
     ```
7. Publish messages to the topic:

   ```sh
    python publisher.py PUBSUB_PROJECT_ID publish TOPIC_ID
   ```
8. Read the messages published to the topic:

   - Retrieve messages from your pull subscription:

     ```sh
     python subscriber.py PUBSUB_PROJECT_ID receive SUBSCRIPTION_ID
     ```
   - Observe the messages delivered to your local push endpoint. For example, messages look like the following:

     ```sh
     {
       "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, C#, and Rust, if you have set `PUBSUB_EMULATOR_HOST`
as described in [Setting environment variables](https://docs.cloud.google.com/pubsub/docs/emulator.md.txt#env),
the Pub/Sub client libraries automatically call the API running in the
local instance rather than Pub/Sub.

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

### C#


Before trying this sample, follow the C# setup instructions in the
[Pub/Sub quickstart using
client libraries](https://docs.cloud.google.com/pubsub/docs/quickstart-client-libraries).


For more information, see the
[Pub/Sub C# API
reference documentation](https://cloud.google.com/dotnet/docs/reference/Google.Cloud.PubSub.V1/latest).


To authenticate to Pub/Sub, set up Application Default Credentials.
For more information, see

[Set up authentication for a local development environment](https://docs.cloud.google.com/docs/authentication/set-up-adc-local-dev-environment.md.txt).

```c#

using Google.Api.Gax;
using Google.Cloud.PubSub.V1;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

public class EmulatorSupportSample
{
    public async Task WithEmulatorAsync(string projectId, string topicId, string subscriptionId)
    {
        // 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.
        PublisherServiceApiClient publisherService = await new PublisherServiceApiClientBuilder
        {
            EmulatorDetection = EmulatorDetection.EmulatorOrProduction
        }.BuildAsync();

        // Use the client as you'd normally do, to create a topic in this example.
        TopicName topicName = new TopicName(projectId, topicId);
        publisherService.CreateTopic(topicName);

        // Create the SubscriberServiceApiClient using the SubscriberServiceApiClientBuilder
        // and setting the EmulatorDection property.
        SubscriberServiceApiClient subscriberService = await new SubscriberServiceApiClientBuilder
        {
            EmulatorDetection = EmulatorDetection.EmulatorOrProduction
        }.BuildAsync();

        // Use the client as you'd normally do, to create a subscription in this example.
        SubscriptionName subscriptionName = new SubscriptionName(projectId, subscriptionId);
        subscriberService.CreateSubscription(subscriptionName, topicName, pushConfig: null, ackDeadlineSeconds: 60);

        // Create the PublisherClient using PublisherClientBuilder to set the EmulatorDetection property.
        PublisherClient publisher = await new PublisherClientBuilder
        {
            TopicName = topicName,
            EmulatorDetection = EmulatorDetection.EmulatorOrProduction
        }.BuildAsync();
        // Use the client as you'd normally do, to send a message in this example.
        await publisher.PublishAsync("Hello, Pubsub");
        await publisher.ShutdownAsync(TimeSpan.FromSeconds(15));

        // Create the SubscriberClient using SubscriberClientBuild to set the EmulatorDetection property.
        SubscriberClient subscriber = await new SubscriberClientBuilder
        {
            SubscriptionName = subscriptionName,
            EmulatorDetection = EmulatorDetection.EmulatorOrProduction
        }.BuildAsync();
        List<PubsubMessage> receivedMessages = new List<PubsubMessage>();

        // Use the client as you'd normally do, to listen for messages in this example.
        await subscriber.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.
            return Task.FromResult(SubscriberClient.Reply.Ack);
        });
    }
}
```

### Java


Before trying this sample, follow the Java setup instructions in the
[Pub/Sub quickstart using
client libraries](https://docs.cloud.google.com/pubsub/docs/quickstart-client-libraries).


For more information, see the
[Pub/Sub Java API
reference documentation](https://docs.cloud.google.com/java/docs/reference/google-cloud-pubsub/latest/overview).


To authenticate to Pub/Sub, set up Application Default Credentials.
For more information, see

[Set up authentication for a local development environment](https://docs.cloud.google.com/docs/authentication/set-up-adc-local-dev-environment.md.txt).

```java

import com.google.api.core.ApiFuture;
import com.google.api.gax.core.CredentialsProvider;
import com.google.api.gax.core.NoCredentialsProvider;
import com.google.api.gax.grpc.GrpcTransportChannel;
import com.google.api.gax.rpc.FixedTransportChannelProvider;
import com.google.api.gax.rpc.TransportChannelProvider;
import com.google.cloud.pubsub.v1.Publisher;
import com.google.cloud.pubsub.v1.TopicAdminClient;
import com.google.cloud.pubsub.v1.TopicAdminSettings;
import com.google.protobuf.ByteString;
import com.google.pubsub.v1.PubsubMessage;
import com.google.pubsub.v1.Topic;
import com.google.pubsub.v1.TopicName;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

public class UsePubSubEmulatorExample {
  public static void main(String... args) throws Exception {
    String hostport = System.getenv("PUBSUB_EMULATOR_HOST");
    ManagedChannel channel = ManagedChannelBuilder.forTarget(hostport).usePlaintext().build();
    try {
      TransportChannelProvider channelProvider =
          FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel));
      CredentialsProvider credentialsProvider = NoCredentialsProvider.create();

      // Set the channel and credentials provider when creating a `TopicAdminClient`.
      // Can be done similarly for a `SubscriptionAdminClient`.
      TopicAdminClient topicAdminClient =
          TopicAdminClient.create(
              TopicAdminSettings.newBuilder()
                  .setTransportChannelProvider(channelProvider)
                  .setCredentialsProvider(credentialsProvider)
                  .build());

      TopicName topicName = TopicName.of("my-project-id", "my-topic-id");
      Topic topic = 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`.
      Publisher publisher =
          Publisher.newBuilder(topicName)
              .setChannelProvider(channelProvider)
              .setCredentialsProvider(credentialsProvider)
              .build();

      String message = "Hello World!";
      ByteString data = ByteString.copyFromUtf8(message);
      PubsubMessage pubsubMessage = PubsubMessage.newBuilder().setData(data).build();

      ApiFuture<String> messageIdFuture = publisher.publish(pubsubMessage);
      String messageId = messageIdFuture.get();
      System.out.println("Published message ID: " + messageId);
    } finally {
      channel.shutdown();
    }
  }
}
```

### Rust

```rust
use google_cloud_auth::credentials::anonymous::Builder as Anonymous;
use google_cloud_pubsub::client::{Publisher, TopicAdmin};
use google_cloud_pubsub::model::Message;

pub async fn sample(project_id: &str, topic_id: &str) -> anyhow::Result<()> {
    let emulator_host = std::env::var("PUBSUB_EMULATOR_HOST")?;
    let endpoint = format!("http://{emulator_host}");

    let topic_admin = TopicAdmin::builder()
        .with_endpoint(&endpoint)
        .with_credentials(Anonymous::new().build())
        .build()
        .await?;
    let topic = topic_admin
        .create_topic()
        .set_name(format!("projects/{project_id}/topics/{topic_id}"))
        .send()
        .await?;
    println!("created topic: {}", topic.name);

    let publisher = Publisher::builder(topic.name)
        .with_endpoint(&endpoint)
        .with_credentials(Anonymous::new().build())
        .build()
        .await?;
    let message_id = publisher
        .publish(Message::new().set_data("Hello, Emulator!"))
        .await?;
    println!("published message with ID: {message_id}");
    Ok(())
}
```

<br />

## Stopping the emulator

To stop the emulator, press <kbd>Control+C</kbd>.

After you stop the emulator, run the following command to remove
the `PUBSUB_EMULATOR_HOST` environment variable so your application will
connect 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, see
[`gcloud beta emulators pubsub`](https://docs.cloud.google.com/sdk/gcloud/reference/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` and `UpdateSnapshot` RPCs are not supported.
- IAM operations are not supported.
- Configurable message retention is not supported; all messages are retained indefinitely.
- Subscription expiration is not supported. Subscriptions don't expire.
- Schema support for protocol buffers.
- BigQuery subscriptions can be created, but don't send messages to BigQuery.
- 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 a [Public issue tracker](https://issuetracker.google.com/issues/new?component=187173&template=0).

## What's next

- To learn how to use the Pub/Sub emulator with minikube, see this [blog post](https://medium.com/google-cloud/use-pub-sub-emulator-in-minikube-67cd1f289daf).