Introduction
Google Cloud Pub/Sub is the leading asynchronous messaging service for modern event-driven architectures. It decouples producers and consumers at scale while guaranteeing message delivery. In 2026, resilience, ordering, and latency requirements demand deep mastery of advanced features like dead-letter queues, exactly-once delivery, and Avro schemas. This tutorial guides you step by step toward a production-ready implementation.
Prerequisites
- Google Cloud account with billing enabled
- Google Cloud CLI SDK installed and authenticated
- Strong knowledge of TypeScript and Node.js 20+
- Understanding of event-driven patterns and SLAs
Project Setup and Authentication
#!/bin/bash
PROJECT_ID="mon-projet-pubsub-2026"
gcloud config set project $PROJECT_ID
gcloud services enable pubsub.googleapis.com
npm install @google-cloud/pubsub typescript @types/nodeThis command enables the Pub/Sub API and installs the official client. Ensure the service account has Pub/Sub Publisher and Subscriber roles.
Creating a Topic with Advanced Retention
import { PubSub } from '@google-cloud/pubsub';
const pubsub = new PubSub();
async function createAdvancedTopic() {
const topicName = 'orders-topic';
const [topic] = await pubsub.createTopic({
name: topicName,
messageRetentionDuration: { seconds: 86400 * 7 },
messageStoragePolicy: { allowedPersistenceRegions: ['europe-west1'] }
});
console.log(`Topic created: ${topic.name}`);
}
createAdvancedTopic();We set a 7-day retention period and a regional storage policy to meet data sovereignty requirements.
Publishing Messages with Ordering
import { PubSub } from '@google-cloud/pubsub';
const pubsub = new PubSub();
async function publishOrderedMessages() {
const topic = pubsub.topic('orders-topic', { enableMessageOrdering: true });
const messages = [
{ data: Buffer.from(JSON.stringify({orderId: '123', status: 'created'})), orderingKey: '123' },
{ data: Buffer.from(JSON.stringify({orderId: '123', status: 'paid'})), orderingKey: '123' }
];
for (const msg of messages) {
await topic.publishMessage(msg);
}
}
publishOrderedMessages();The orderingKey guarantees delivery order per key. Enable enableMessageOrdering on the topic to activate this critical production feature.
Creating a Subscription with Dead-Letter Queue
import { PubSub } from '@google-cloud/pubsub';
const pubsub = new PubSub();
async function createSubscriptionWithDLQ() {
const topic = pubsub.topic('orders-topic');
const dlqTopic = pubsub.topic('orders-dlq');
await dlqTopic.create();
const [subscription] = await topic.createSubscription('orders-processing', {
deadLetterPolicy: {
deadLetterTopic: dlqTopic.name,
maxDeliveryAttempts: 5
},
ackDeadlineSeconds: 60
});
console.log(`Subscription created: ${subscription.name}`);
}
createSubscriptionWithDLQ();The dead-letter queue automatically isolates unprocessed messages after 5 attempts, preventing data loss while enabling later manual handling.
Consuming with Exactly-Once and Retry
import { PubSub } from '@google-cloud/pubsub';
const pubsub = new PubSub();
async function consumeWithExactlyOnce() {
const subscription = pubsub.subscription('orders-processing');
subscription.on('message', async (message) => {
try {
const data = JSON.parse(message.data.toString());
await processOrder(data);
message.ack();
} catch (error) {
console.error('Processing error:', error);
message.nack();
}
});
}
async function processOrder(order: any) {
// Critical business logic
console.log('Processing order:', order.orderId);
}
consumeWithExactlyOnce();nack() enables controlled retries. Combine with DLQ for maximum resilience. Avoid long-running processing inside the handler.
Best Practices
- Always enable ordering when event sequence is critical
- Configure dead-letter queues with a limited number of attempts
- Use Avro or Protobuf schemas to ensure message compatibility
- Monitor backlog and latency metrics via Cloud Monitoring
- Limit message size to 10 MB and prefer batch publishing
Common Errors to Avoid
- Forgetting to enable enableMessageOrdering on the topic before using ordering keys
- Not configuring a dead-letter queue, causing infinite retry loops
- Ignoring message deserialization errors without proper nack
- Using pull subscriptions without flow control, leading to timeouts
Going Further
Deepen your skills with our advanced Google Cloud training. Also explore event-driven architecture patterns and integration with Cloud Run and Dataflow.