Google Cloud Pub/Sub Triggers

Cloud Functions uses event-driven functions to handle events from your Cloud infrastructure. For example, Cloud Functions can be triggered by messages published to Pub/Sub topics in the same Cloud project as the function. Pub/Sub is a globally distributed message bus that automatically scales as you need it and provides a foundation for building your own robust, global services.

Event types

There is a single Pub/Sub event used by Cloud Functions, and it has the trigger type value google.pubsub.topic.publish.

This event is sent when a message is published to a Pub/Sub topic that is specified when a function is deployed. Every message published to this topic will trigger function execution with message contents passed as input data.

Event structure

Cloud Functions triggered from a Pub/Sub topic will be sent events conforming to the PubsubMessage type, with the caveat that publishTime and messageId are not directly available in the PubsubMessage. Instead, you can access publishTime and messageId via the event ID and timestamp properties of the event metadata. This metadata is accessible via the context object that is passed to your function when it is invoked.

The payload of the PubsubMessage object, the data published to the topic, is stored as a base64-encoded string in the data attribute of the PubsubMessage. To extract the payload of the PubsubMessage object, you may need to decode the data attribute as shown in the examples below.

Sample code


 * Background Cloud Function to be triggered by Pub/Sub.
 * This function is exported by index.js, and executed when
 * the trigger topic receives a message.
 * @param {object} message The Pub/Sub message.
 * @param {object} context The event metadata.
exports.helloPubSub = (message, context) => {
  const name =
    ? Buffer.from(, 'base64').toString()
    : 'World';

  console.log(`Hello, ${name}!`);


def hello_pubsub(event, context):
    """Background Cloud Function to be triggered by Pub/Sub.
         event (dict):  The dictionary with data specific to this type of
                        event. The `@type` field maps to
                        The `data` field maps to the PubsubMessage data
                        in a base64-encoded string. The `attributes` field maps
                        to the PubsubMessage attributes if any is present.
         context ( Metadata of triggering event
                        including `event_id` which maps to the PubsubMessage
                        messageId, `timestamp` which maps to the PubsubMessage
                        publishTime, `event_type` which maps to
                        `google.pubsub.topic.publish`, and `resource` which is
                        a dictionary that describes the service API endpoint
              , the triggering topic's name, and
                        the triggering event type
        None. The output is written to Cloud Logging.
    import base64

    print("""This Function was triggered by messageId {} published at {} to {}
    """.format(context.event_id, context.timestamp, context.resource["name"]))

    if 'data' in event:
        name = base64.b64decode(event['data']).decode('utf-8')
        name = 'World'
    print('Hello {}!'.format(name))


// Package helloworld provides a set of Cloud Functions samples.
package helloworld

import (

// PubSubMessage is the payload of a Pub/Sub event.
// See the documentation for more details:
type PubSubMessage struct {
	Data []byte `json:"data"`

// HelloPubSub consumes a Pub/Sub message.
func HelloPubSub(ctx context.Context, m PubSubMessage) error {
	name := string(m.Data) // Automatically decoded from base64.
	if name == "" {
		name = "World"
	log.Printf("Hello, %s!", name)
	return nil


import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.Logger;

public class HelloPubSub implements BackgroundFunction<Message> {
  private static final Logger logger = Logger.getLogger(HelloPubSub.class.getName());

  public void accept(Message message, Context context) {
    String name = "world";
    if (message != null && message.getData() != null) {
      name = new String(
    }"Hello %s!", name));


import java.util.Base64
import java.util.logging.Logger

class EventExample {
    companion object {
        var log: Logger = Logger.getLogger(

    fun helloPubSub(message: PubSubMessage) {
        val data = String(Base64.getDecoder().decode(

data class PubSubMessage(
    val data: String,
    val messageId: String,
    val publishTime: String,
    val attributes: Map<String, String>


using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using Google.Events.Protobuf.Cloud.PubSub.V1;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;

namespace HelloPubSub
    public class Function : ICloudEventFunction<MessagePublishedData>
        private readonly ILogger _logger;

        public Function(ILogger<Function> logger) =>
            _logger = logger;

        public Task HandleAsync(CloudEvent cloudEvent, MessagePublishedData data, CancellationToken cancellationToken)
            string nameFromMessage = data.Message?.TextData;
            string name = string.IsNullOrEmpty(nameFromMessage) ? "world" : nameFromMessage;
            _logger.LogInformation("Hello {name}", name);
            return Task.CompletedTask;


require "functions_framework"
require "base64"

FunctionsFramework.cloud_event "hello_pubsub" do |event|
  # The event parameter is a CloudEvents::Event::V1 object.
  # See
  name = Base64.decode64["message"]["data"] rescue "World"

  # A cloud_event function does not return a response, but you can log messages
  # or cause side effects such as sending additional events. "Hello, #{name}!"


use CloudEvents\V1\CloudEventInterface;
use Google\CloudFunctions\FunctionsFramework;

// Register the function with Functions Framework.
// This enables omitting the `FUNCTIONS_SIGNATURE_TYPE=cloudevent` environment
// variable when deploying. The `FUNCTION_TARGET` environment variable should
// match the first parameter.
FunctionsFramework::cloudEvent('helloworldPubsub', 'helloworldPubsub');

function helloworldPubsub(CloudEventInterface $event): void
    $log = fopen(getenv('LOGGER_OUTPUT') ?: 'php://stderr', 'wb');

    $cloudEventData = $event->getData();
    $pubSubData = base64_decode($cloudEventData['message']['data']);

    $name = $pubSubData ? htmlspecialchars($pubSubData) : 'World';
    fwrite($log, "Hello, $name!" . PHP_EOL);

Publishing a message from within a function

You can also publish a message to a Pub/Sub topic from within a function. This lets you trigger subsequent Cloud Function invocations using Cloud Pub/Sub messages. You can use this technique to:

  • Chain sequential function calls together.
  • Distribute (or "fan out") groups of tasks in parallel across multiple Cloud Function instances.

In the following example, an HTTP publish function sends a message to a Pub/Sub topic, and that in turn triggers a subscribe function.

This snippet shows the publish function that publishes a message to a Pub/Sub topic.


const {PubSub} = require('@google-cloud/pubsub');

// Instantiates a client
const pubsub = new PubSub();

 * Publishes a message to a Cloud Pub/Sub Topic.
 * @example
 * gcloud functions call publish --data '{"topic":"[YOUR_TOPIC_NAME]","message":"Hello, world!"}'
 *   - Replace `[YOUR_TOPIC_NAME]` with your Cloud Pub/Sub topic name.
 * @param {object} req Cloud Function request context.
 * @param {object} req.body The request body.
 * @param {string} req.body.topic Topic name on which to publish.
 * @param {string} req.body.message Message to publish.
 * @param {object} res Cloud Function response context.
exports.publish = async (req, res) => {
  if (!req.body.topic || !req.body.message) {
        'Missing parameter(s); include "topic" and "message" properties in your request.'

  console.log(`Publishing message to topic ${req.body.topic}`);

  // References an existing topic
  const topic = pubsub.topic(req.body.topic);

  const messageObject = {
    data: {
      message: req.body.message,
  const messageBuffer = Buffer.from(JSON.stringify(messageObject), 'utf8');

  // Publishes a message
  try {
    await topic.publish(messageBuffer);
    res.status(200).send('Message published.');
  } catch (err) {
    return Promise.reject(err);


import base64
import json
import os

from import pubsub_v1

# Instantiates a Pub/Sub client
publisher = pubsub_v1.PublisherClient()

# Publishes a message to a Cloud Pub/Sub topic.
def publish(request):
    request_json = request.get_json(silent=True)

    topic_name = request_json.get("topic")
    message = request_json.get("message")

    if not topic_name or not message:
        return ('Missing "topic" and/or "message" parameter.', 400)

    print(f'Publishing message to topic {topic_name}')

    # References an existing topic
    topic_path = publisher.topic_path(PROJECT_ID, topic_name)

    message_json = json.dumps({
        'data': {'message': message},
    message_bytes = message_json.encode('utf-8')

    # Publishes a message
        publish_future = publisher.publish(topic_path, data=message_bytes)
        publish_future.result()  # Verify the publish succeeded
        return 'Message published.'
    except Exception as e:
        return (e, 500)


// Package contexttip is an example of how to use Pub/Sub and context.Context in
// a Cloud Function.
package contexttip

import (


// GOOGLE_CLOUD_PROJECT is a user-set environment variable.
var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")

// client is a global Pub/Sub client, initialized once per instance.
var client *pubsub.Client

func init() {
	// err is pre-declared to avoid shadowing client.
	var err error

	// client is initialized with context.Background() because it should
	// persist between function invocations.
	client, err = pubsub.NewClient(context.Background(), projectID)
	if err != nil {
		log.Fatalf("pubsub.NewClient: %v", err)

type publishRequest struct {
	Topic   string `json:"topic"`
	Message string `json:"message"`

// PublishMessage publishes a message to Pub/Sub. PublishMessage only works
// with topics that already exist.
func PublishMessage(w http.ResponseWriter, r *http.Request) {
	// Parse the request body to get the topic name and message.
	p := publishRequest{}

	if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
		log.Printf("json.NewDecoder: %v", err)
		http.Error(w, "Error parsing request", http.StatusBadRequest)

	if p.Topic == "" || p.Message == "" {
		s := "missing 'topic' or 'message' parameter"
		http.Error(w, s, http.StatusBadRequest)

	m := &pubsub.Message{
		Data: []byte(p.Message),
	// Publish and Get use r.Context() because they are only needed for this
	// function invocation. If this were a background function, they would use
	// the ctx passed as an argument.
	id, err := client.Topic(p.Topic).Publish(r.Context(), m).Get(r.Context())
	if err != nil {
		log.Printf("topic(%s).Publish.Get: %v", p.Topic, err)
		http.Error(w, "Error publishing message", http.StatusInternalServerError)
	fmt.Fprintf(w, "Message published: %v", id)


import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class PublishMessage implements HttpFunction {
  // TODO<developer> set this environment variable
  private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT");

  private static final Logger logger = Logger.getLogger(PublishMessage.class.getName());

  public void service(HttpRequest request, HttpResponse response) throws IOException {
    Optional<String> maybeTopicName = request.getFirstQueryParameter("topic");
    Optional<String> maybeMessage = request.getFirstQueryParameter("message");

    BufferedWriter responseWriter = response.getWriter();

    if (maybeTopicName.isEmpty() || maybeMessage.isEmpty()) {

      responseWriter.write("Missing 'topic' and/or 'message' parameter(s).");

    String topicName = maybeTopicName.get();"Publishing message to topic: " + topicName);

    // Create the PubsubMessage object
    ByteString byteStr = ByteString.copyFrom(maybeMessage.get(), StandardCharsets.UTF_8);
    PubsubMessage pubsubApiMessage = PubsubMessage.newBuilder().setData(byteStr).build();

    Publisher publisher = Publisher.newBuilder(
        ProjectTopicName.of(PROJECT_ID, topicName)).build();

    // Attempt to publish the message
    String responseMessage;
    try {
      responseMessage = "Message published.";
    } catch (InterruptedException | ExecutionException e) {
      logger.log(Level.SEVERE, "Error publishing Pub/Sub message: " + e.getMessage(), e);
      responseMessage = "Error publishing Pub/Sub message; see logs for more info.";


This snippet shows the subscribe function that is triggered when the message is published to the Pub/Sub topic:


 * Triggered from a message on a Cloud Pub/Sub topic.
 * @param {object} pubsubMessage The Cloud Pub/Sub Message object.
 * @param {string} The "data" property of the Cloud Pub/Sub Message.
exports.subscribe = pubsubMessage => {
  // Print out the data from Pub/Sub, to prove that it worked
  console.log(Buffer.from(, 'base64').toString());


# Triggered from a message on a Cloud Pub/Sub topic.
def subscribe(event, context):
    # Print out the data from Pub/Sub, to prove that it worked


import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.logging.Logger;

public class SubscribeToTopic implements BackgroundFunction<Message> {
  private static final Logger logger = Logger.getLogger(SubscribeToTopic.class.getName());

  public void accept(Message message, Context context) {
    if (message.getData() == null) {"No message provided");

    String messageString = new String(

In production, you might use the cURL command-line utility to invoke the publish function, as follows:

curl -X POST  -d "{\"topic\": \"PUBSUB_TOPIC\", \"message\":\"YOUR_MESSAGE\"}" -H "Content-Type: application/json"

But for testing and debugging, you could instead use the gcloud functions call command to call the function directly. The following steps describe how to run the above example using the gcloud functions call command:

  1. Create a Pub/Sub topic, where MY_TOPIC is the name of the new topic you are creating:

    gcloud pubsub topics create MY_TOPIC
  2. Deploy the publish function, where RUNTIME is the name of the runtime you are using, such as nodejs8:

    gcloud functions deploy publish --trigger-http --runtime RUNTIME
  3. Deploy the subscribe function:

    gcloud functions deploy subscribe --trigger-topic MY_TOPIC --runtime RUNTIME
  4. Directly invoke the publish function using the gcloud functions call command, and supply the required data as JSON in the --data argument:

    gcloud functions call publish --data '{"topic":"MY_TOPIC","message":"Hello World!"}'
  5. Check the logs for the subscribe function. Note that it may take a few minutes for your results to appear in the log:

    gcloud functions logs read subscribe

You should see output resembling the following:

D    ...Function execution started
I    ...{"data":{"message":"Hello World!"}}
D    ...Function execution took 753 ms, finished with status: 'ok'

Deploying your function

The following gcloud command deploys a function that will be triggered when a message is published to a Pub/Sub topic:

gcloud functions deploy FUNCTION_NAME --entry-point ENTRY_POINT --trigger-topic TOPIC_NAME FLAGS...
Argument Description
FUNCTION_NAME The registered name of the Cloud Function you are deploying. This can either be the name of a function in your source code, or an arbitrary string. If FUNCTION_NAME is an arbitrary string, then you must include the --entry-point flag.
--entry-point ENTRY_POINT The name of a function or class in your source code. Optional, unless you did not use FUNCTION_NAME to specify the function in your source code to be executed during deployment. In that case, you must use --entry-point to supply the name of the executable function.
--trigger-topic TOPIC_NAME The name of the Pub/Sub topic to which the function is subscribed. If the topic doesn't exist, it is created during deployment.
FLAGS... Additional flags you must specify during deployment, such as --runtime. For a full reference, see the gcloud functions deploy documentation.

See the Pub/Sub Tutorial for a complete example of how to use Pub/Sub triggers.

Legacy Cloud Pub/Sub triggers

The gcloud command below deploys a function that is triggered by legacy Pub/Sub notifications on a specific topic. These notifications are supported for legacy functions already consuming these events. However, we recommend using the --trigger-topic flag instead, as the legacy notifications might be removed at a future date.

gcloud functions deploy FUNCTION_NAME \
--trigger-resource TOPIC_NAME \
--trigger-event providers/cloud.pubsub/eventTypes/topic.publish \

Next steps

See the Pub/Sub Tutorial for an example of how to implement an event-driven function that is triggered by Pub/Sub.