GCP Pub/Sub Basics
This skill provides safe, repeatable guidance for operating Google Cloud Pub/Sub
from the
CLI. It covers the core messaging concepts, the IAM roles
required to act on resources, step-by-step recipes for creating topics and
subscriptions, and the operational guardrails that prevent destructive or
ambiguous actions. Follow it whenever you provision, inspect, or operate Pub/Sub
infrastructure for event-driven systems, streaming pipelines, or asynchronous
service integrations.
Overview
Google Cloud Pub/Sub is a fully managed, asynchronous messaging service that
decouples message producers from message consumers. Producers publish messages
without knowing who consumes them, and consumers receive messages without
knowing who produced them. This decoupling enables resilient, horizontally
scalable, event-driven architectures.
Core concepts
-
Topic — A named resource to which producers (publishers) send messages.
A topic is the entry point for data flowing into the system. Topics may
optionally enforce a schema on incoming messages.
-
Subscription — A named resource representing a stream of messages from a
single topic to be delivered to a subscribing application. Each subscription
receives its own independent copy of every message published to the topic
after the subscription was created. A topic can have many subscriptions; this
is the fan-out mechanism.
-
Pull delivery — The subscriber application explicitly requests messages
from the subscription on its own schedule (using a client library, the CLI, or
a streaming pull connection). Pull is well suited to high-throughput batch
consumers and workers that control their own concurrency. Messages must be
explicitly acknowledged (acked) after successful processing.
-
Push delivery — Pub/Sub proactively sends each message as an HTTPS POST
request to a configured
endpoint (for example a Cloud Run service, Cloud
Functions function, or any publicly reachable HTTPS URL). The endpoint
acknowledges a message by returning a success HTTP status (
,
,
,
, or
). Push is well suited to serverless consumers and
webhook-style integrations.
-
Acknowledgement (ack) and ack deadline — A consumer must acknowledge a
message to signal successful processing. If the message is not acked within the
subscription's ack deadline, Pub/Sub redelivers it. This at-least-once
delivery model means consumers must be designed to be idempotent.
-
Dead Letter Topic (DLT) — A topic to which messages are forwarded after a
subscription fails to deliver them more than a configured maximum number of
times (
). Dead lettering isolates "poison" messages
so they stop blocking healthy traffic and can be inspected or reprocessed
later. The Pub/Sub service account must have permission to publish to the dead
letter topic and to subscribe to the source subscription.
-
Schema — An optional, versioned definition (Avro or Protocol Buffer) that
constrains the structure of messages published to a topic. When a topic is
associated with a schema and an encoding (
or
), Pub/Sub
validates every published message and rejects non-conforming payloads. Schemas
provide a contract between producers and consumers and prevent malformed data
from entering the pipeline.
Prerequisites
Before performing any operation, confirm the following are in place.
-
Enable the Pub/Sub API. The
service must be
enabled on the target project.
gcloud services enable pubsub.googleapis.com --project=PROJECT_ID
-
Install and update the gcloud CLI. Operations in this skill assume a
recent Google Cloud CLI. Confirm it is installed and current.
gcloud version
gcloud components update --quiet
-
Authorize the CLI. Authenticate with an identity (user or service
account) that holds the required roles described below.
gcloud auth login
gcloud config set project PROJECT_ID
For automated or non-interactive environments, prefer Application Default
Credentials backed by a dedicated service account:
gcloud auth activate-service-account --key-file=KEY_FILE_PATH
-
Confirm the active project and account. Always verify the execution
context before mutating resources.
gcloud config list --format="value(core.project,core.account)"
Key IAM roles
Grant the least privilege required for the task. The principal acting
through this skill should hold only the roles that match its responsibilities.
| Role | Role ID | Purpose |
|---|
| Pub/Sub Admin | | Full control: create, update, and delete topics, subscriptions, and schemas, and manage IAM policies. Restrict to provisioning identities. |
| Pub/Sub Publisher | | Publish messages to topics. Grant to producer services. |
| Pub/Sub Subscriber | | Consume and acknowledge messages from subscriptions. Grant to consumer services. |
| Pub/Sub Viewer | | Read-only access to view topics, subscriptions, schemas, and configuration. Grant for inspection and auditing. |
| Service Account User | roles/iam.serviceAccountUser
| Allows an identity to act as (impersonate) a service account. Required when configuring authenticated push subscriptions that invoke a service using a service-account identity token. |
Additional notes:
- Push subscriptions that call private services (for example an authenticated
Cloud Run endpoint) require that the push service account is granted the
invoker role on the target service (for example ), in
addition to
roles/iam.serviceAccountUser
on that service account for the
configuring identity.
- Dead letter delivery requires the Pub/Sub service agent
(
service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com
) to hold
on the dead letter topic and
on the source subscription.
Composite resource deployment recipe
Use this composite recipe when you need to provision a new schema-bound topic and subscription together. It orchestrates the configuration, validation, and creation of the dependent resources (Schema -> Topic -> Subscription) in a single execution block to minimize shell turns and prevent partial configurations.
bash
# Run as a single copy-pasteable execution block
(
set -e
# 1. Configuration Parameters
PROJECT_ID="PROJECT_ID"
SCHEMA_ID="SCHEMA_ID"
SCHEMA_TYPE="avro" # avro or protocol-buffer
SCHEMA_FILE="PATH_TO_SCHEMA_FILE" # Local path to schema definition file
ENCODING="json" # json or binary
TOPIC_ID="TOPIC_ID"
SUBSCRIPTION_ID="SUBSCRIPTION_ID"
ACK_DEADLINE=60 # Acknowledgement deadline in seconds
echo "=== [1/5] Validating Schema Definition ==="
gcloud pubsub schemas validate-schema \
--type="${SCHEMA_TYPE}" \
--definition-file="${SCHEMA_FILE}" \
--project="${PROJECT_ID}"
echo "=== [2/5] Creating Schema ==="
gcloud pubsub schemas create "${SCHEMA_ID}" \
--type="${SCHEMA_TYPE}" \
--definition-file="${SCHEMA_FILE}" \
--project="${PROJECT_ID}" \
--quiet
echo "=== [3/5] Creating Topic ==="
gcloud pubsub topics create "${TOPIC_ID}" \
--schema="${SCHEMA_ID}" \
--message-encoding="${ENCODING}" \
--project="${PROJECT_ID}" \
--quiet
echo "=== [4/5] Creating Subscription ==="
gcloud pubsub subscriptions create "${SUBSCRIPTION_ID}" \
--topic="${TOPIC_ID}" \
--ack-deadline="${ACK_DEADLINE}" \
--project="${PROJECT_ID}" \
--quiet
echo "=== [5/5] Verifying Resources ==="
gcloud pubsub schemas describe "${SCHEMA_ID}" --project="${PROJECT_ID}"
gcloud pubsub topics describe "${TOPIC_ID}" --project="${PROJECT_ID}"
gcloud pubsub subscriptions describe "${SUBSCRIPTION_ID}" --project="${PROJECT_ID}"
)
Schema enforcement: "JSON" is a message encoding, not a schema type
This trips up almost everyone. Google Cloud Pub/Sub has two
schema types:
and
. There is no
schema type, and
gcloud pubsub schemas create --type=json
will fail.
When a task asks for a "JSON schema" or "strict JSON validation," it means the
topic validates messages with JSON encoding against an attached schema. JSON
is the
you set on the
topic, not the type of the schema.
The schema definition itself is normally written in AVRO.
So a request for a "strict JSON schema" breaks into two parts:
- A schema attached to the topic (the data contract).
- The topic's set to (messages validated as JSON).
Correct recipe
bash
SCHEMA="orders-schema"
TOPIC="orders-topic"
# 1. Create the schema. Type is avro; the definition is written in Avro JSON.
gcloud pubsub schemas create "$SCHEMA" \
--type=avro \
--definition='{"type":"record","name":"Order","fields":[
{"name":"id","type":"string"},
{"name":"amount","type":"double"}
]}'
# 2. Create the topic and bind the schema with JSON MESSAGE ENCODING.
# --message-encoding=json is the part that makes it a "JSON schema".
gcloud pubsub topics create "$TOPIC" \
--schema="$SCHEMA" \
--message-encoding=json
# 3. Verify the contract: encoding must be json.
gcloud pubsub topics describe "$TOPIC" --format="value(schemaSettings.encoding)" # -> json
If a topic already exists, bind the schema and encoding with
gcloud pubsub topics update "$TOPIC" --schema="$SCHEMA" --message-encoding=json
.
Default to JSON encoding unless a task explicitly asks for binary. Reach for
--message-encoding=binary
only when the requirement calls for it. Choosing
binary (or omitting the encoding) is the most common reason a "JSON schema"
requirement is scored as unmet, because the schema looks present but the
messages are not JSON-validated.
Troubleshooting
- "Schema is AVRO but I need JSON": That is a category error. AVRO is the
schema type; JSON is the message encoding. Keep the AVRO schema and set the
topic's . Do not try to change the schema type.
- Encoding shows empty / BINARY: the topic was created without
(or without ). Re-bind with
gcloud pubsub topics update --schema=... --message-encoding=json
.
Creating topics and subscriptions
All commands below use placeholders in CAPS. Replace
,
,
,
, and similar tokens with concrete
values before execution. Every command explicitly scopes the project with
and runs non-interactively with
.
1. Create a topic
gcloud pubsub topics create TOPIC_ID \
--project=PROJECT_ID \
--quiet
To create a topic that enforces a message-retention duration (so that even
subscriptions can replay within the window):
gcloud pubsub topics create TOPIC_ID \
--message-retention-duration=7d \
--project=PROJECT_ID \
--quiet
To associate a topic with an existing schema:
gcloud pubsub topics create TOPIC_ID \
--schema=SCHEMA_ID \
--message-encoding=json \
--project=PROJECT_ID \
--quiet
2. Create a Pull subscription
A pull subscription lets the consumer fetch messages on demand. The
controls how long a consumer has to acknowledge a message
before redelivery.
gcloud pubsub subscriptions create SUBSCRIPTION_ID \
--topic=TOPIC_ID \
--ack-deadline=60 \
--project=PROJECT_ID \
--quiet
To attach a dead letter topic and bound redelivery attempts:
gcloud pubsub subscriptions create SUBSCRIPTION_ID \
--topic=TOPIC_ID \
--ack-deadline=60 \
--dead-letter-topic=DEAD_LETTER_TOPIC_ID \
--max-delivery-attempts=5 \
--project=PROJECT_ID \
--quiet
To restrict which messages this subscription receives using a server-side
filter on message attributes (see Data Reduction below):
gcloud pubsub subscriptions create SUBSCRIPTION_ID \
--topic=TOPIC_ID \
--message-filter='attributes.eventType = "ORDER_CREATED"' \
--project=PROJECT_ID \
--quiet
3. Create a Push subscription
A push subscription delivers each message to an HTTPS
. The endpoint
must return a success status to acknowledge a message.
gcloud pubsub subscriptions create SUBSCRIPTION_ID \
--topic=TOPIC_ID \
--push-endpoint=ENDPOINT \
--ack-deadline=60 \
--project=PROJECT_ID \
--quiet
For an authenticated push subscription that targets a private service, attach a
push-auth service account so Pub/Sub sends a signed OIDC token:
gcloud pubsub subscriptions create SUBSCRIPTION_ID \
--topic=TOPIC_ID \
--push-endpoint=ENDPOINT \
--push-auth-service-account=PUSH_SERVICE_ACCOUNT_EMAIL \
--ack-deadline=60 \
--project=PROJECT_ID \
--quiet
4. Verify what you created
After creation, confirm configuration before relying on it.
gcloud pubsub topics describe TOPIC_ID \
--project=PROJECT_ID
gcloud pubsub subscriptions describe SUBSCRIPTION_ID \
--project=PROJECT_ID
Resource naming and verification checklist
Before completing any Pub/Sub provisioning task, run through this checklist to ensure all resources match expectations:
Core principles
These principles are mandatory. Apply them to every Pub/Sub operation.
Explicit command validation (mandatory)
- Before running any mutating command, restate in plain language what the command
will do and to which resource. Confirm the resource name, the project, and the
effect.
- Use where the subcommand supports it, or run the read-only
/ equivalent first to confirm the current state.
- Never execute a command whose effect you cannot precisely predict. If the
outcome is ambiguous, stop and validate first.
Data reduction
Minimize the volume of data fetched, processed, and returned. Large,
unfiltered reads are slow, costly, and noisy.
- — Cap the number of results when listing or pulling. For
example,
gcloud pubsub subscriptions pull SUBSCRIPTION_ID --limit=10
.
- Server-side filtering — Apply at subscription creation
so unwanted messages are never delivered, rather than filtering after the
fact. Use on commands to narrow results server-side where
supported.
- Projection — Request only the fields you need with
or instead of dumping full
resource representations.
Project and location scoping
- Always append to every command. Never rely solely on
the ambient project; explicit scoping prevents acting on the
wrong project.
- For resources that support location or regional endpoints, specify the
location explicitly rather than depending on defaults.
Execution constraints
- Non-interactive mode — Append (or ) to suppress interactive
prompts so commands are deterministic and automation-safe. This must not be
used to bypass the human-approval requirements in the Safety section below.
- Single commands — Execute one discrete command at a time. Do not
chain unrelated operations into a single invocation.
- No raw shell operators — Do not use shell pipes (), redirects (,
), command substitution (), background operators (), or
/ chaining to compose Pub/Sub commands. Each command must stand alone
and be independently auditable.
Safety and guardrails
[!CAUTION]
Pub/Sub operations can be destructive and irreversible. Deleting a topic or
subscription permanently discards undelivered messages and breaks every
producer and consumer bound to it. Changing IAM policy can silently cut off
access for production services. Treat every mutating operation as
production-impacting unless explicitly proven otherwise.
Prohibited operations (denylist)
The following operations MUST NOT be executed without explicit, recorded human
approval. When a task appears to require one of these, stop and request
approval first; describe the exact command and its blast radius.
- Deleting a topic —
gcloud pubsub topics delete ...
. Destroys the topic
and detaches all subscriptions.
- Deleting a subscription —
gcloud pubsub subscriptions delete ...
.
Permanently drops all unacknowledged messages held by that subscription.
- Deleting or modifying a schema —
gcloud pubsub schemas delete ...
or
schema revision changes that can invalidate in-flight producers.
- Purging/seeking messages destructively —
gcloud pubsub subscriptions seek ...
to a timestamp or snapshot that discards the current backlog.
- Changing critical IAM bindings — Adding, removing, or replacing
, , or
bindings on production topics or subscriptions, or any
operation that replaces an entire policy.
- Detaching a topic —
gcloud pubsub topics detach-subscription ...
, which
immediately stops delivery to the affected subscription.
Always-safe operations
Read-only inspection commands (
,
, and bounded
without
auto-ack for diagnostics) are safe and encouraged for validation, provided they
respect the data-reduction principles above.
Troubleshooting / What to do if...
...a command fails with a permission error (PERMISSION_DENIED / 403)
- Confirm the active identity:
gcloud config list --format="value(core.account)"
.
- Confirm the role on the resource matches the action (see the IAM table). For
example, publishing requires ; consuming requires
.
- For push to private endpoints, verify the push service account has the
invoker role on the target service and that the configuring identity holds
roles/iam.serviceAccountUser
on that service account.
- Confirm the API is enabled:
gcloud services list --enabled --filter="pubsub" --project=PROJECT_ID
.
...a subscription has a growing backlog (messages not being consumed fast enough)
- Inspect the backlog and oldest unacked age in Cloud Monitoring metrics
(
subscription/num_undelivered_messages
,
subscription/oldest_unacked_message_age
).
- For pull consumers, scale out the number of consumer instances or increase
per-instance concurrency so total throughput exceeds the publish rate.
- Confirm consumers are acking successfully; failed processing leads to
redelivery and inflated backlog.
- Consider whether a should reduce delivered volume, or
whether the topic is over-fanned-out.
...messages accumulate unacknowledged (repeated redelivery)
- Verify the consumer is calling acknowledge after successful processing.
- Check the . If processing routinely takes longer than the
deadline, increase it or extend the deadline programmatically; otherwise
Pub/Sub redelivers before the consumer finishes.
- Ensure consumers are idempotent — at-least-once delivery guarantees that
duplicates can occur, and non-idempotent handlers compound the problem.
- If specific "poison" messages never succeed, attach a dead letter topic
with so they are isolated instead of redelivered
forever.
...schema validation fails (published messages are rejected)
- Confirm the topic's bound schema and encoding:
gcloud pubsub topics describe TOPIC_ID --project=PROJECT_ID
.
- Validate a sample message against the schema before publishing:
gcloud pubsub schemas validate-message ...
.
- Confirm the producer serializes with the encoding the topic expects
( vs ); a mismatch causes rejection even for structurally
valid data.
- If the schema legitimately needs to change, commit a new, compatible schema
revision rather than editing producers ad hoc — and treat schema deletion as
a prohibited operation requiring approval.
Reference directory
Consult these reference documents for deeper, task-specific detail:
- — Comprehensive
command reference, including publishing, pulling,
acknowledging, seeking, snapshots, and output formatting recipes.
references/iam-security.md
— Detailed IAM role
and policy guidance, least-privilege patterns, service-account configuration
for push delivery, and dead-letter permission setup.
references/client-libraries.md
— Pointers
to the official Google Cloud client libraries for programmatic publishing and
consuming, with notes on when to prefer SDK code over the CLI.