Firebase Cloud Functions and the bazillion other services that power it
If you’re a mobile developer and want to build an app yourself, you probably reach a point where you realize that you need some sort of backend. That’s exactly where I found myself with my recent idea.
While I would judge my backend skills above average, and have even implemented some backends on Vercel in Go in the past, this time I decided to go all in on Firebase.
I don’t want to focus on learning or exploring new things. Instead, I finally want to build something that I can actually finish. I can only finish something when I use a software stack I’m familiar with, without getting stuck in endless hours of exploring new things. While it’s generally fun and I really enjoy such journeys, I always end up with a half-baked product. This time, it should be different.
The irony of this blog post: I wouldn’t have written it if I had only used software that I’m 100% familiar with. While I’m familiar with the concept of “Functions”, I’ve never used Firebase Cloud Functions (FCF).
Anyway, while the FCF documentation has a section about “How does it work? — Lifecycle of a background function” that includes some information on which services are used, I was still a bit shocked by what it’s actually using behind the scenes when deploying a function.
I like to know how stuff works and where my resources are located. This is especially true in this case, because using FCF requires you to upgrade to the Blaze — pay as you go — plan. So when it comes to your own money, you probably want to know even more which services are used and when they actually incur cost for you.
This blog is about demystifying what Google Cloud Platform (GCP) services are used when creating and deploying a “simple” function on FCF.
Starting with a quick overview of “Cloud Functions” in general. Obviously, to execute your functions, some software and hardware around it are required. While, for example, Vercel hides this concept from you, it is pretty visible on FCF. I don’t know what I like more, honestly. But judging that is not what this blog is about.
Anyway, to execute a function, you need to:
- Have a running server (“hardware”)
- Compile the code, depending on the language
- Have a web server that locates your function and executes it
The question now is: how does this work on GCP?
It’s good to know that all Firebase projects are GCP projects as well! There is no difference. If I understand it correctly, a Firebase project is basically a GCP project with just Firebase APIs and services enabled. So the first thing to know here, if you don’t already know it, is that you can also see your Firebase project in the Google Cloud Console.
With that said, you literally have the freedom to enable and use any GCP services within your Firebase project. And GCP has a lot more to offer than Firebase. And the Cloud Functions feature from Firebase makes exact use of this.
Google Cloud Storage
When deploying a function, FCF zips your code and saves it in a “special” Cloud Storage bucket prefixed with gcf. After deploying, you can explore the bucket here.
This is used to, well, store your function’s source code.
Google Cloud Build
To package your function into a web server, it uses Cloud Build as a continuous delivery server. Cloud Run is somehow triggered when you deploy your function using the Cloud Storage zip file as the source. You can find the Cloud Build runs here.
What’s interesting is that when you explore the logs, you can see that it’s pulling Docker images from various places to get things done. For example, the gcs-fetcher image or the builder/python image. The first is obviously used to fetch Google Cloud Storage (gcs) data (our function source code), while the latter is probably the “web server” part.
Also noteworthy is that it doesn’t build a binary. Instead, it creates a Docker image and…
Google Artifact Registry
Deploy the image to the Artifact Registry. Generally speaking, the Artifact Registry is a package manager for all your artifacts. It can be used to store several types of things. In this case, it stores the Docker image created in the previous step, which now contains a complete web app including your function, ready to be executed when needed. The image can be found here inside the gcf-artifacts repository.
Google Cloud Run
The last piece of the puzzle is Cloud Run. According to their documentation, the service can be used “to develop frontend and backend services”. You can deploy any Docker image there. Alternatively, you can deploy source code directly, which will be wrapped into a Docker image and executed as a container. If you go the latter route, it will probably follow the same round trip as FCF.
Speaking of FCF, it takes the image from the Artifact Registry and runs it as a container when the function is invoked.
Your Cloud Run services can be found here.
Bonus: Google Secret Manager
I had an LLM write the Python function I deployed. The code contained a SecretParam, which turns out to be part of a “password manager” for GCP — Secret Manager. It is probably deeply integrated into other GCP services as well, and therefore also into FCF.
You can simply create a key-value pair via the Firebase CLI, for example, store it in the Secret Manager, and have it be read by your function.
These are probably all GCP services that are needed and used to provide a Firebase Cloud Function. Each of them provides a monthly free quota, so you likely won’t be charged while exploring functions. You can check which services offer what for free here or here.
However, all the APIs and services are automatically enabled as soon as you deploy an FCF. As mentioned above, you have to be in the Blaze plan to use them. So even though there are free quotas for literally all services, you still have to provide a billing account and have to “fear” that you make a mistake and then pay for it. Just think about an endless loop in your function that keeps calling itself over and over.
There are, of course, some things you can set up to get notified about the current pricing. But as far as I know, there’s no way to say “If the cost hits more than X [Currency]/Month, shut down all services”. Which is a bit odd.
I hope this gave you some insight into what happens behind the scenes when using Firebase Cloud Functions. It was a bit surprising to me how many Google Cloud Platform services are actually used to power them. Since it required me to upgrade to the Blaze plan, I was also a bit worried about pricing and potential costs. I’m always a little uneasy when things get automatically enabled, because I fear side effects that I don’t yet fully understand or can’t easily observe. That was one of the reasons I wrote this post. On the other hand, I now have a better understanding of some GCP services that I want to look into at some point anyway 😅.
