Skip to content

Instantly share code, notes, and snippets.

@radvansky-tomas
Created May 16, 2025 10:56
Show Gist options
  • Save radvansky-tomas/e7c6947f83f45c5fe9c98209075e4cd4 to your computer and use it in GitHub Desktop.
Save radvansky-tomas/e7c6947f83f45c5fe9c98209075e4cd4 to your computer and use it in GitHub Desktop.

Dart in the Cloud: A Journey with GCP Cloud Functions, Firestore, and Protobufs

In the ever-evolving landscape of cloud computing, choosing the right language and tools for your serverless functions can significantly impact performance, maintainability, and developer experience. This article explores my journey of leveraging Dart for Google Cloud Platform (GCP) Cloud Functions, focusing on Firestore triggers, Eventarc, and the power of Protocol Buffers (Protobufs).

Why Dart for GCP Cloud Functions?

Dart, with its strong typing, AOT (Ahead-of-Time) compilation, and excellent performance, presents a compelling option for serverless functions. While Node.js has traditionally been a popular choice, Dart offers potential benefits in terms of execution speed and type safety, which can be crucial for complex, data-driven applications.

Cloud Run: The Foundation

Although this article focuses on Cloud Functions, it's worth noting that Dart's capabilities extend seamlessly to Cloud Run. Whether you're building containerized applications or event-driven functions, Dart provides a robust and efficient runtime.

Firestore Triggers and Eventarc: Real-time Data Processing

A core requirement for many applications is reacting to changes in a database. GCP's Firestore, a NoSQL document database, combined with Eventarc, provides a powerful mechanism for triggering functions based on database events.

I utilized Firestore triggers to process data changes in real-time. Eventarc serves as the underlying eventing infrastructure, allowing Cloud Functions to subscribe to these events reliably. This setup enables building reactive systems that respond instantly to data modifications.

Working with Protobufs: Efficient Data Handling

When dealing with structured data in event-driven architectures, Protobufs offer a highly efficient and language-agnostic way to serialize and deserialize data. For Firestore triggers, the event payload often comes in a Protobuf format.

Decoding Protobuf Payloads in Dart

Decoding Protobuf payloads in Dart is straightforward using the protobuf package. The key is to have the correct .proto definitions for the event data. For Firestore events, Google provides these definitions (e.g., google.events.cloud.firestore.v1.Data).

// Example of how you might decode a Firestore event payload
// Assuming you have the generated Dart classes from your .proto files
import 'package:my_protos/google/events/cloud/firestore/v1/data.pb.dart';

void handleFirestoreEvent(dynamic eventData) {
  // The actual event data might be nested or need specific casting
  // This is a simplified example
  try {
    final firestoreEvent = FirestoreEventData.fromBuffer(eventData);
    print('Old value: ${firestoreEvent.oldValue}');
    print('New value: ${firestoreEvent.value}');
    // ... process the event
  } catch (e) {
    print('Error decoding Protobuf: $e');
  }
}

Using Protobufs ensures that data is handled in a type-safe and performant manner, reducing the chances of runtime errors and improving deserialization speed.

Performance Gains: Dart vs. Node.js

One of the key motivators for exploring Dart in this context was its potential for performance improvements over Node.js, especially for CPU-intensive tasks and faster cold starts.

(Placeholder for screenshots and detailed performance comparison to be added by the user)

My findings indicate a noticeable performance gain when using Dart, particularly in scenarios involving complex data transformations and frequent invocations.

Challenges and Workarounds

While the journey has been largely positive, there are a few areas where the Dart ecosystem for GCP, particularly around Firebase tooling, could be improved.

Missing Firebase Emulator Support

Currently, comprehensive Firebase Emulator support for Dart functions, especially for Firestore triggers, is lacking. This makes local development and testing more challenging, requiring deployments to a test GCP project for full end-to-end testing.

Absence of Automatic Firebase Deploy CLI Tool and Auto Discovery

Unlike some other languages, there isn't a dedicated Firebase CLI command (e.g., firebase deploy --only functions) that automatically discovers and deploys Dart Cloud Functions with the same ease. This requires a more manual or scripted deployment process.

Terraform and Firestore Triggers: An Ongoing Issue

I initially attempted to manage the infrastructure, including Firestore triggers for Cloud Functions, using Terraform. However, I encountered an ongoing issue with Terraform's ability to correctly configure Firestore triggers with Eventarc. This seems to be a known limitation or bug within the provider at the time of writing.

Solution: Semi-Automatic Approach with Cloud Build and gcloud

To overcome these deployment challenges, I opted for a semi-automatic approach. This involves:

  1. Using a cloudbuild.yaml file to define the build and deployment steps.
  2. Leveraging gcloud CLI commands within the Cloud Build script to deploy the function and configure the Eventarc trigger for Firestore.

This approach, while not as seamless as a fully integrated CLI experience, provides a reliable and repeatable deployment process.

# Example snippet from cloudbuild.yaml for deploying a function and setting up a trigger
steps:
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
  args:
  - gcloud
  - functions
  - deploy
  - myDartFunction
  - --region=YOUR_REGION
  - --runtime=dart
  - --trigger-event-filters="type=google.cloud.firestore.document.v1.written"
  - --trigger-event-filters="database=(default)"
  - --trigger-event-filters-path-pattern="documents/myCollection/{docId}"
  - --entry-point=myDartFunctionHandler
  # ... other necessary flags

Conclusion

Using Dart for GCP Cloud Functions, especially with Firestore triggers and Protobufs, has proven to be a powerful and performant combination. The strong typing, compilation to native code, and efficient data handling contribute to a robust serverless architecture.

While there are some rough edges, particularly concerning Firebase tooling integration and Terraform support for Firestore triggers, these can be navigated with custom scripting and the gcloud CLI. As the Dart ecosystem on GCP continues to mature, I expect these areas to improve, making Dart an even more attractive option for cloud development.

The journey highlights the importance of choosing the right tools for the job, and for my use case, Dart has delivered significant benefits despite the current limitations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment