OpsCanary
gcppubsubPractitioner

Mastering Dead Letter Topics in Pub/Sub for Reliable Messaging

5 min read Google Cloud DocsApr 28, 2026
Share
PractitionerHands-on experience recommended

Dead letter topics exist to solve a common problem in messaging systems: what happens when a message can't be delivered? When subscribers fail to acknowledge a message, Pub/Sub retries delivery until the acknowledgment deadline is met or the message expires. If the message remains undeliverable after a configured number of attempts, it gets forwarded to a dead letter topic. This ensures that no message is lost, allowing for further inspection or reprocessing later.

When configuring a subscription with a dead letter topic, you need to set the maximum number of delivery attempts. The default is 5, but you can adjust this based on your application's requirements. When a message is forwarded to the dead letter topic, Pub/Sub wraps the original message in a new one and adds attributes that identify the source subscription. This makes it easier to trace back the message's origin and understand why it failed.

In production, it's essential to create a dedicated topic for your dead-letter configuration. This helps keep your messaging system organized and allows for better monitoring of undeliverable messages. Be aware that if your dead-letter topic is in a different project, you'll need to specify that project during configuration. Understanding these nuances will help you avoid common pitfalls and ensure your messaging remains reliable.

Key takeaways

  • Configure the maximum number of delivery attempts to control message retries.
  • Use dead letter topics to prevent message loss and enable further processing.
  • Wrap original messages in new ones when forwarding to dead letter topics for traceability.

Why it matters

In production, undeliverable messages can lead to data loss and application failures. Dead letter topics provide a safety net, ensuring that you can handle these scenarios gracefully and maintain system reliability.

Code examples

gcloud
gcloud pubsub subscriptions create subscription-id --topic=topic-id --dead-letter-topic=dead-letter-topic-name [--max-delivery-attempts=max-delivery-attempts] [--dead-letter-topic-project=dead-letter-topic-project]
C++
namespace pubsub = ::google::cloud::pubsub; namespace pubsub_admin = ::google::cloud::pubsub_admin; [](pubsub_admin::SubscriptionAdminClient client, std::string const& project_id, std::string const& topic_id, std::string const& subscription_id, std::string const& dead_letter_topic_id, int dead_letter_delivery_attempts) { google::pubsub::v1::Subscription request; request.set_name(pubsub::Subscription(project_id, subscription_id).FullName()); request.set_topic(pubsub::Topic(project_id, topic_id).FullName()); request.mutable_dead_letter_policy()->set_dead_letter_topic(pubsub::Topic(project_id, dead_letter_topic_id).FullName()); request.mutable_dead_letter_policy()->set_max_delivery_attempts(dead_letter_delivery_attempts); auto sub = client.CreateSubscription(request); if (sub.status().code() == google::cloud::StatusCode::kAlreadyExists) { std::cout << "The subscription already exists\n"; return; } if (!sub) throw std::move(sub).status(); std::cout << "The subscription was successfully created: " << sub->DebugString() << "\n"; std::cout << "It will forward dead letter messages to: " << sub->dead_letter_policy().dead_letter_topic() << "\n"; std::cout << "After " << sub->dead_letter_policy().max_delivery_attempts() << " delivery attempts.\n"; }
C#
using Google.Cloud.PubSub.V1; using System; public class CreateSubscriptionWithDeadLetterPolicySample { public Subscription CreateSubscriptionWithDeadLetterPolicy(string projectId, string topicId, string subscriptionId, string deadLetterTopicId) { SubscriberServiceApiClient subscriber = SubscriberServiceApiClient.Create(); var subscriptionName = SubscriptionName.FromProjectSubscription(projectId, subscriptionId); var topicName = TopicName.FromProjectTopic(projectId, topicId); var deadLetterTopic = TopicName.FromProjectTopic(projectId, deadLetterTopicId).ToString(); var subscriptionRequest = new Subscription { SubscriptionName = subscriptionName, TopicAsTopicName = topicName, DeadLetterPolicy = new DeadLetterPolicy { DeadLetterTopic = deadLetterTopic, MaxDeliveryAttempts = 10 }, AckDeadlineSeconds = 30 }; var subscription = subscriber.CreateSubscription(subscriptionRequest); Console.WriteLine("Created subscription: " + subscription.SubscriptionName.SubscriptionId); Console.WriteLine($"It will forward dead letter messages to: {subscription.DeadLetterPolicy.DeadLetterTopic}"); Console.WriteLine($"After {subscription.DeadLetterPolicy.MaxDeliveryAttempts} delivery attempts."); return subscription; }}

When NOT to use this

The official docs don't call out specific anti-patterns here. Use your judgment based on your scale and requirements.

Want the complete reference?

Read official docs

Test what you just learned

Quiz questions written from this article

Take the quiz →

Get the daily digest

One email. 5 articles. Every morning.

No spam. Unsubscribe anytime.