# Pub/Sub emulator

> Run Pub/Sub locally: topics, subscriptions, push and pull delivery, acknowledgements, dead-letter retries, and schemas on port 5383.
>
> Source: https://local.cloud/services/pubsub/

Pub/Sub is asynchronous messaging between publishers and subscribers. Topics decouple event producers from the applications that process those events.

## Typical uses

Use when several consumers need to react to the same event independently of its publisher. Consumers acknowledge completed work and handle retries without blocking the producer.

Examples

- Event-driven application pipelines
- Background processing and fan-out

Connection

Environment variable

`PUBSUB_EMULATOR_HOST=localhost:5383`

Runtime details

- **Endpoints:** gRPC :5383
- **Minimum tier:** Community
- **Persistence:** service-data
- **Implementation:** Local Facade

## Example usage

Service ID: `pubsub`. Starts by default. Use an already running LocalCloud runtime for the examples below.

Export the local project and mapped endpoints in your client process, then use the client settings below. [First-time setup](https://local.cloud/docs/)

```bash
# Export GOOGLE_CLOUD_PROJECT and PUBSUB_EMULATOR_HOST
eval "$(localcloud env)"
```

REST gateway examples use the generated HTTP address in `SERVICE_USAGE_EMULATOR_HOST`; native SDKs can use a different protocol.

Python:

### Python

### Publish and acknowledge a message

Send, receive, and acknowledge an event; Pub/Sub lets producers and consumers work independently.

A repeatable topic, subscription, publish, and pull example.

SDK dependencies

Run in a new example directory

```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install google-cloud-pubsub
```

#### Save as hello.py

```python
import os
from uuid import uuid4
from google.cloud import pubsub_v1

assert os.environ['PUBSUB_EMULATOR_HOST']
project = os.environ['GOOGLE_CLOUD_PROJECT']
publisher = pubsub_v1.PublisherClient()
subscriber = pubsub_v1.SubscriberClient()
name = 'hello-' + uuid4().hex[:12]
topic = publisher.topic_path(project, name)
subscription = subscriber.subscription_path(project, name)

publisher.create_topic(request={'name': topic}, timeout=30)
try:
    subscriber.create_subscription(request={'name': subscription, 'topic': topic}, timeout=30)
    try:
        publisher.publish(topic, b'Hello, Pub/Sub!').result(timeout=30)
        response = subscriber.pull(request={'subscription': subscription, 'max_messages': 1}, timeout=30)
        assert response.received_messages
        for received in response.received_messages:
            print(received.message.data.decode())
            subscriber.acknowledge(request={'subscription': subscription, 'ack_ids': [received.ack_id]}, timeout=30)
    finally:
        subscriber.delete_subscription(request={'subscription': subscription}, timeout=30)
finally:
    publisher.delete_topic(request={'topic': topic}, timeout=30)
    subscriber.close()
    publisher.transport.close()
```

#### Run the example

```bash
python hello.py
```

#### Verify the result

The command completes successfully and prints the expected output shown below.

#### Expected output

```
Hello, Pub/Sub!
```

[Full example guide](https://local.cloud/docs/sdk-examples/#pubsub-python)

Java:

### Java

### Create a topic and publish a message

Publish a message to a new topic; Pub/Sub lets producers send events independently of their consumers.

Java needs an explicit plaintext channel and no-credentials provider. Requires JDK 17+ and Maven.

SDK dependencies

Run in a new example directory

```bash
cat > pom.xml <<'XML'
<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>example</groupId><artifactId>local-example</artifactId><version>1</version>
  <dependencies><dependency>
    <groupId>com.google.cloud</groupId><artifactId>google-cloud-pubsub</artifactId><version>1.157.0</version>
  </dependency></dependencies>
</project>
XML
mvn -q dependency:build-classpath -Dmdep.outputFile=classpath.txt
```

#### Save as Hello.java

```java
import com.google.api.gax.core.NoCredentialsProvider;
import com.google.api.gax.grpc.GrpcTransportChannel;
import com.google.api.gax.rpc.FixedTransportChannelProvider;
import com.google.cloud.pubsub.v1.*;
import com.google.protobuf.ByteString;
import com.google.pubsub.v1.*;
import io.grpc.ManagedChannelBuilder;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class Hello {
  public static void main(String[] args) throws Exception {
    var host = Objects.requireNonNull(System.getenv("PUBSUB_EMULATOR_HOST"));
    var project = Objects.requireNonNull(System.getenv("GOOGLE_CLOUD_PROJECT"));
    var channel = ManagedChannelBuilder.forTarget(host).usePlaintext().build();
    var transport = FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel));
    var credentials = NoCredentialsProvider.create();
    var settings = TopicAdminSettings.newBuilder()
        .setTransportChannelProvider(transport).setCredentialsProvider(credentials).build();
    try (var topics = TopicAdminClient.create(settings)) {
      var topic = TopicName.of(project, "example-" + UUID.randomUUID());
      topics.createTopic(topic);
      try {
        var publisher = Publisher.newBuilder(topic)
            .setChannelProvider(transport).setCredentialsProvider(credentials).build();
        try {
          var message = PubsubMessage.newBuilder()
              .setData(ByteString.copyFromUtf8("Hello from LocalCloud!")).build();
          System.out.println(publisher.publish(message).get(30, TimeUnit.SECONDS));
        } finally {
          publisher.shutdown();
          publisher.awaitTermination(30, TimeUnit.SECONDS);
        }
      } finally {
        topics.deleteTopic(topic);
      }
    } finally {
      channel.shutdownNow();
    }
  }
}
```

#### Run the example

```bash
java --class-path "$(cat classpath.txt)" Hello.java
```

#### Verify the result

Publishing returns a message ID, and the finally block deletes the temporary topic. This checks publishing; use the Python or gcloud example to verify subscriber delivery.

gcloud CLI:

### gcloud CLI

### Publish and pull a message

Publish, pull, and acknowledge a message; Pub/Sub decouples event producers from background consumers.

gcloud uses the gateway REST endpoint, while SDKs use PUBSUB\_EMULATOR\_HOST.

#### Configure gcloud CLI

```bash
: "${SERVICE_USAGE_EMULATOR_HOST:?Export the LocalCloud environment first}"
export CLOUDSDK_CORE_PROJECT="${GOOGLE_CLOUD_PROJECT:?Export the LocalCloud environment first}"
export CLOUDSDK_AUTH_DISABLE_CREDENTIALS=true
export CLOUDSDK_API_ENDPOINT_OVERRIDES_PUBSUB="${SERVICE_USAGE_EMULATOR_HOST%/}/"
```

#### Run in your terminal

```bash
(
set -e
TOPIC="example-$(date +%s)-$$"
SUBSCRIPTION="$TOPIC-sub"
gcloud pubsub topics create "$TOPIC"
trap 'gcloud pubsub topics delete "$TOPIC" --quiet' EXIT
gcloud pubsub subscriptions create "$SUBSCRIPTION" --topic="$TOPIC"
trap 'gcloud pubsub subscriptions delete "$SUBSCRIPTION" --quiet; gcloud pubsub topics delete "$TOPIC" --quiet' EXIT
gcloud pubsub topics publish "$TOPIC" --message="Hello from LocalCloud!"
gcloud pubsub subscriptions pull "$SUBSCRIPTION" --auto-ack --limit=1
)
```

#### Verify the result

The pulled message contains Hello from LocalCloud!. The trap removes the subscription and topic on exit; verify the message contents before treating the test as successful.

Verify a resource workflow by creating isolated state, performing the operation, and reading the result back. Run cleanup even after a failure; delete only test-owned resources.

Connection failed? Check `localcloud status --verbose`, enabled services, and client exports. Stop accidental Google Cloud calls; correct local routing before retrying.

## Documented workflows

- ### Topics, subscriptions, push/pull, StreamingPull, and acknowledgements

    Create a topic and subscription, publish a fixture, and receive it through pull, StreamingPull, or push. Acknowledge successful work and check how the consumer handles an expired acknowledgment deadline.

- ### Attribute filters, dead-letter forwarding, and retries

    Publish events with matching and nonmatching attributes to test subscription filters. Make a handler fail, then inspect retries and dead-letter forwarding instead of treating publication as delivery proof.

- ### Retention, snapshots, and timestamp/snapshot seek

    Create a snapshot before acknowledging test messages, then seek to the snapshot or a retained timestamp. Verify which messages are delivered again and use the new acknowledgment IDs.

- ### Avro/Protobuf schemas, revisions, and JSON/binary validation

    Register an Avro or Protobuf schema and its revisions, then publish valid and invalid JSON or binary payloads. Assert that invalid batches fail before the consumer receives them.

- ### Wrapped and unwrapped push payloads with optional metadata headers

    Configure noWrapper to deliver raw message bytes and enable writeMetadata when the receiver needs message headers. Test the default wrapped JSON path separately from unwrapped delivery.

- ### Expiration and message-storage policy configuration readback

    Set subscription expirationPolicy and topic messageStoragePolicy, then read them back over the API and after restart. These settings support configuration tests; they do not expire subscriptions or relocate messages locally.

- ### Authenticated push with locally signed OIDC tokens

    Configure an OIDC service account and audience on a push subscription. Have the receiver validate the locally signed bearer token against the LocalCloud issuer and JWKS before accepting the message.

## Service boundaries

- No exactly-once delivery, message ordering, export subscriptions, or transforms
- Push receivers must trust the local issuer/JWKS; retry and retention timing is approximate
- Expiration and storage policies are metadata; stored IAM does not enforce publish or topic deletion

## Code examples and integrations

- [Build an integration test loop](https://local.cloud/gcp-integration-testing/): Start the runtime, verify readiness, exercise your SDK, and clean up test state.
- [Official SDK code samples](https://docs.cloud.google.com/pubsub/docs/samples): Browse language-specific samples. Adapt endpoints and use the local workflows listed above.

Agent testing

## Use Pub/Sub with an AI agent

Before the agent changes application logic, have it create local Pub/Sub state, read it back with the project SDK, and note which feature the check covered. That first local call catches accidental production routing and needs no GCP account, service-account key, or billing project.

### Pub/Sub local test

```
Use LocalCloud to test Pub/Sub locally. Read https://local.cloud/ai/agents.md, set PUBSUB_EMULATOR_HOST=localhost:5383, create a topic and subscription, publish one test message, pull or stream it, ack it, and verify the payload without using real GCP credentials.
```

Production endpoints, auth, IAM, quotas, regional behavior, and final release validation still need the target Google Cloud project.

[Agent resources](https://local.cloud/ai/) has more prompts and the AGENTS.md template.

## Pub/Sub emulator FAQ

### How do I run Pub/Sub locally?

Start LocalCloud using the setup guide, then export its environment in the same terminal as your application.

### Which environment variable points the SDK at the local Pub/Sub?

LocalCloud exports PUBSUB\_EMULATOR\_HOST=localhost:5383. Use the generated value, because the CLI picks another port when the default is in use. Some SDKs also need explicit client endpoint options; the variable alone does not route them locally.

### Does the local Pub/Sub behave exactly like Google Cloud?

No. LocalCloud runs the documented workflows on this page within the service boundaries listed here. Validate behavior against real Pub/Sub before production deployment.

## Related guides

- [Compatibility](https://local.cloud/compatibility/): compare all 27 service guides.
- [Configuration](https://local.cloud/docs/configuration/): service selection and runtime settings.
- [Official Pub/Sub documentation](https://docs.cloud.google.com/pubsub/docs/overview): service concepts and cloud usage.
