Updated Nov 5, 20267 min read

What Is Google Cloud Pub/Sub? Topics, Subscriptions and Pull vs Push

Google Cloud Pub/Sub is GCP's managed messaging service. How topics and subscriptions work, when to use pull vs push, what ack deadlines and ordering keys do, how dead-letter topics catch failures, and how to get Pub/Sub from application code.

Google Cloud Pub/Sub is GCP's managed messaging service: publishers send messages to a topic, and every subscription on that topic gets its own copy. Pub/Sub stores the messages, delivers them by pull or push, and redelivers until a subscriber acknowledges. You do not run brokers or partition managers.

Most of the complexity sits around the topic rather than in the publish call: pull versus push, acknowledgment deadlines, ordering keys, dead-letter topics, and the IAM and Terraform that surround every environment. This guide covers those pieces and how Encore provisions GCP Pub/Sub from Pub/Sub declared in code.

Google Cloud Pub/Sub at a glance

What Pub/Sub doesWhat stays with you
HostingFully managed topics and subscriptionsChoosing pull, push or export
DeliveryAt least once by default; exactly-once opt-inIdempotent consumers
Fan-outOne copy per subscription on a topicDesigning subscription names and handlers
Hiding in-flight workAcknowledgment deadline (default 10 seconds)Matching deadline to handler duration
OrderingOrdering keys, enabled per subscriptionPicking a stable key and handling head-of-line blocking
FailuresDead-letter topic after 5 to 100 delivery attemptsSetting max attempts, alarming, replaying
Size and retentionUp to 10 MB per message; retain up to 31 days (default 7)Payload design, retention choice
SecurityIAM on topics and subscriptionsService accounts and least privilege

How topics and subscriptions work

A publisher calls the Pub/Sub API (or a client library) and sends a message to a topic. The message is stored redundantly. Each subscription attached to that topic receives an independent copy, so email and shipping can each process order-placed at their own pace. A subscription that falls behind grows its own backlog without slowing the others.

Delivery is at least once by default, so a message can arrive twice even after a successful ack. Handlers should be idempotent, for example with an insert that uses ON CONFLICT DO NOTHING on the order ID. Subscriptions can enable exactly-once delivery within a region when duplicates are costly.

Messages can be up to 10 MB. Retention defaults to 7 days and can go up to 31 days on the topic or subscription. Unacknowledged messages kept longer than 24 hours incur extra storage charges.

Pull vs push subscriptions

Pull subscriptions suit high throughput and long-running workers. Your client requests messages, can batch them, controls concurrency, and can extend the acknowledgment deadline while work is in progress. Multiple pull clients on the same subscription load-balance messages among themselves.

Push subscriptions suit webhook-style endpoints. Pub/Sub POSTs each message to an HTTPS URL with a non-self-signed certificate. That fits Cloud Run, Cloud Functions and App Engine when you want Pub/Sub to drive delivery instead of running a long-lived receive loop. Flow control is mostly on the server side; returning an HTTP error signals that the endpoint is overloaded.

Export subscriptions write messages straight into BigQuery, Cloud Storage or Bigtable without your own subscriber process, useful when the destination is a data store and you do not need custom processing first. The subscription type comparison covers when each option fits.

Acknowledgment deadlines, ordering keys and dead-letter topics

The acknowledgment deadline is the initial window after delivery during which the message is leased to the subscriber. The default is 10 seconds; the allowed range is 10 to 600 seconds. Client libraries often extend the deadline while the handler runs. If the message is neither acked nor nacked before the lease ends, Pub/Sub redelivers it.

Message ordering is optional. When it is enabled on the subscription and the publisher sets an ordering key, messages with the same key in the same region are delivered in publish order. Later messages wait on earlier ones for that key, so a stuck handler can block the rest of the key (head-of-line blocking). Use ordering when sequence for an entity matters; otherwise leave it off for higher parallelism.

A dead-letter topic receives messages that exceed a maximum delivery attempt count (default 5, configurable from 5 to 100). The Pub/Sub service account needs publisher permission on the dead-letter topic and subscriber permission on the source subscription, or forwarding silently fails. Alarm on dead-letter depth, fix the consumer, then replay.

Pub/Sub vs Amazon SQS at a high level

Pub/Sub is built around topics: one publish fans out to every subscription. Amazon SQS is a queue: one consumer takes each message, and fan-out usually means an SNS topic in front of several SQS queues. Pub/Sub offers pull and push natively; SQS is pull-based (Lambda event source mapping is a separate integration). Pub/Sub allows larger messages (10 MB vs 1 MiB) and longer retention (31 vs 14 days). For a deeper comparison, see Google Pub/Sub vs SQS and SQS vs Kafka. For the AWS queue model on its own, see What is Amazon SQS.

How Encore provisions GCP Pub/Sub

Encore

Encore is infrastructure from code for TypeScript and Go, with a platform that provisions and deploys into your own AWS or GCP account. You declare a topic and subscriptions in code, and on GCP Encore creates GCP Pub/Sub topics and subscriptions with dead-letter topics, as listed in the GCP infrastructure docs. On AWS the same declarations become SNS and SQS with dead-letter queues.

The Infrastructure page in the Encore dashboard with a database's configuration panel open, showing fields for vCPUs, memory, storage, availability type, max connections and backups.
Each provisioned resource can be reviewed and its configuration edited per environment in the Encore dashboard. The screenshot shows a GCP Cloud SQL database.

Set up the app

Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

~
$ encore app create shop --example=go/hello-world$ cd shop && mkdir orders

A topic and a subscription are package-level declarations next to the code that uses them:

// orders/orders.go package orders import ( "context" "time" "encore.dev/pubsub" "encore.dev/rlog" ) type OrderPlaced struct { OrderID string `json:"order_id"` } // GCP Pub/Sub on GCP, SNS and SQS on AWS. var OrderPlacedTopic = pubsub.NewTopic[*OrderPlaced]("order-placed", pubsub.TopicConfig{ DeliveryGuarantee: pubsub.AtLeastOnce, }) type PlaceParams struct { OrderID string `json:"order_id"` } //encore:api public method=POST path=/orders func Place(ctx context.Context, p *PlaceParams) error { _, err := OrderPlacedTopic.Publish(ctx, &OrderPlaced{OrderID: p.OrderID}) return err } var _ = pubsub.NewSubscription(OrderPlacedTopic, "send-confirmation", pubsub.SubscriptionConfig[*OrderPlaced]{ Handler: sendConfirmation, MaxConcurrency: 50, AckDeadline: time.Minute, RetryPolicy: &pubsub.RetryPolicy{MaxRetries: 10}, }, ) // Returning an error nacks the message; after MaxRetries it goes to the dead-letter topic. func sendConfirmation(ctx context.Context, ev *OrderPlaced) error { rlog.Info("sending confirmation", "order_id", ev.OrderID) return nil }

The same model in TypeScript uses Topic and Subscription from encore.dev/pubsub:

// orders/topics.ts import { Topic, Subscription } from "encore.dev/pubsub"; export interface OrderPlaced { orderId: string; } export const orderPlaced = new Topic<OrderPlaced>("order-placed", { deliveryGuarantee: "at-least-once", }); const _ = new Subscription(orderPlaced, "send-confirmation", { handler: async (event) => { // Send the confirmation for event.orderId. }, });

encore run delivers messages with an in-memory implementation, so publishing and handling work locally without the Pub/Sub emulator or a GCP project. The local development dashboard shows the publish and the handler in its traces. AckDeadline defaults to 30 seconds if unset; after MaxRetries the message moves to the subscription's dead-letter topic, as covered in the Go Pub/Sub docs and the TypeScript Pub/Sub docs.

On deploy to GCP, Encore provisions the topic, the subscription and its dead-letter topic, runs the service on Cloud Run or GKE, and gives each service its own service account with the Pub/Sub permissions it needs, as described in the GCP infrastructure docs, so no topic IDs or keys sit in config. Connecting GCP is covered in deploying to your own cloud. An AI coding agent adding a consumer writes one NewSubscription in the service that needs it, and the same change provisions the subscription on the next deploy.

Best fit: Go and TypeScript teams who want GCP Pub/Sub in their own GCP project, provisioned from the code that publishes and handles messages.

Good to know

  • Make every handler idempotent; at-least-once delivery means duplicates will happen.
  • Prefer pull for high-throughput workers and push when a public HTTPS endpoint is the natural consumer.
  • Grant the Pub/Sub service account publisher rights on any dead-letter topic, or dead-lettering will not move messages.

Frequently asked questions

What is Google Cloud Pub/Sub used for?

Google Cloud Pub/Sub is a fully managed messaging service on GCP. Publishers send messages to a topic, and every subscription on that topic receives its own copy. Typical uses are fanning an order-placed event to email and shipping workers, streaming events into analytics, and buffering work for background jobs.

What is the difference between pull and push subscriptions?

With a pull subscription, your client requests messages from Pub/Sub and controls flow, batching and ack deadline extensions. With a push subscription, Pub/Sub delivers each message as an HTTPS POST to an endpoint you configure, which fits Cloud Run, Cloud Functions and other webhook-style handlers.

How does Google Cloud Pub/Sub differ from Amazon SQS?

Pub/Sub is topic-based: one publish reaches every subscription. SQS is a queue where one consumer takes each message, and fan-out usually needs SNS in front of several SQS queues. Pub/Sub messages can be up to 10 MB and retained up to 31 days; SQS messages are up to 1 MiB and retained up to 14 days.

How do I create a GCP Pub/Sub topic between Go services without managing topics myself?

With Encore, declare a topic with pubsub.NewTopic and a handler with pubsub.NewSubscription, then publish with Publish. Messages are delivered locally without the emulator, and on GCP Encore provisions the topic, subscription and dead-letter topic in your project.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders