Firebase is Google’s all-in-one platform for app development, a useful tool in our day-to-day projects. Because it has so many facets and features, there are several approaches to structuring Firebase code. In an effort to find the most efficient, functional method, we tried several, each with its own unique pros and cons.
In our first interactions with Firebase, we had a couple of pressing questions: where would we put our backend code? And how will it be structured? There are several ways to implement the backend using Firebase, and we tried three different ways.
1. Building a REST API with Google Cloud Functions
Firebase Cloud Functions’ coolest feature, perhaps, is the ability to build a RESTful API without having to write a ton of overhead code for routing or similar actions.
Instead, you can define the URL as part of your function name, then simply write the code that should be executed whenever a request hits that endpoint. The only issue here is that filtering for allowed HTTP verbs must take place inside the function.
Want to incorporate Express.js into your cloud function code? No problem. With Firebase, you can. This web app framework for Node.js allows you to build powerful REST APIs without servers, accessing all the advantages that serverless APIs offer.
This was the first approach we used to implement our backend. We implemented a cloud function for every necessary function and database operation. This method is much cleaner than the alternatives. We could put all our backend code in one place rather than writing it in every front end we use. This way, we could simply call a specific HTTP API and get what we want – nice, clean, and effective.
Additionally, this approach helps us avoid writing spaghetti JavaScript code on the front end. To us, it just feels wrong to put so much backend manipulation right there in front of the end-user.
Despite all these advantages, this approach wasn’t without drawbacks. For example, the Cloud Functions were extremely slow and often suffered from cold starts. In fact, Firebase cold starts seem to happen all the time. Leave a function alone for a few minutes? You can expect a cold start. After some Googling, we discovered that we’re not alone in our cold start complaints. Plenty of other users have experienced similar performance delays. We can live with anything under a second, but in my testing, I routinely experienced 4–5-second delays. That’s simply not acceptable for anything at the production-level.
Pros
All the backend code is gathered in one place.
Easier and cleaner.
Efficient for heavy and background tasks.
Avoids writing spaghetti code of JavaScript on the front end.
Hides backend manipulation from the end-user.
Cons
Slower than using the Firebase SDK in the front end.
Cold starts.
Stops repeatedly when on the free tier.
When to use this approach
There are specific cases where Cloud Functions excel. They can be used for intensive tasks that would be very heavy to run on the front end. Or, they can be used to run background jobs. Although you’ll probably only want to use them when you don’t need an immediate response, so their delays don’t hinder your efficiency.
Cloud Functions also let you react to data changes. Let's say you want to send a welcome email to every new user: you could define a Cloud Function that sends this email every time a new node is appended to the users' path. These functions allow you to run the code you would typically run server-side when writes happen. As you can see, Cloud Functions are fairly versatile. They work for a broad range of cases like intensive tasks, background jobs, side-effects (like sending an email), caching data in an external service, caching data within Firebase for easier reads, analytics, and more.
2. Using the Firebase SDK in the front end
One of Firebase’s main strengths is that it provides an SDK in various languages to access its database (Cloud Firestore/Realtime Database), so you can fetch the data you need or commit data updates without an intermediate custom API layer. If your application is simple and lightweight, this solution can give you great performance.
But before you dive in headfirst, consider this approach’s consequences. Firebase gives you the flexibility to access the database through its different SDK variants. However, if you have several clients (IOS, Android, Web), you could end up writing the same backend code over and over for each one. As a result, you have to continuously ensure consistency. All your teams must be on the same page and in agreement on how to follow the exact same steps to keep the database consistent.
Pros
The SDK provides very fast database access.
Easy approach for simple and lightweight applications.
An escape from the limited quota of the cloud functions on the free tier.
Cons
Spaghetti code of JavaScript on the front end.
The same code has to be written for all front ends (Web/Android/IOS, etc..).
The backend code is exposed in the front end.
Will be slow on the front end if tasks are intensive or heavy.
When to use this approach
When you need to make database updates, whether fetching or committing, the Firebase SDK can work well, as it offers strong speed and performance. But be careful, because writing extensive front-end code will result in spaghetti code. And if you have an intricate, multi-platform app, you should take a different route. Implementing a complicated application on several platforms using this approach can get messy and will require you to write a lot of replicate code.
3. Use an HTTP wrapper.
Go ahead and develop your own server using Node.js, Express.js, or whatever framework you prefer. This server will act as a wrapper for all your communication with Firebase through HTTP endpoints. Of course, this method will be slower than using the Firebase SDK directly. For each endpoint you call, you will need to call a remote server which then calls the remote Firebase. It creates a more time-consuming relay system. Beyond that, when you build your own backend, you lose Firebase’s unique features, so you’ll need to deal with your own server infrastructure and scaling.
Pros
All the backend code is gathered in one place.
Easier and cleaner.
Efficient for heavy and background tasks.
Avoids writing spaghetti code of JavaScript on the front end.
Hides backend manipulation from the end-user.
Avoids Cloud Functions’ frequent delays and cold starts.
Cons
Slower than using the Firebase SDK in the front end.
Adds more complexity, like deployment, hosting, other configurations, and the setup necessary to run a server.
You will have to handle server infrastructure and scaling by yourself.
When to use this approach
Using this approach, we hit the sweet spot between the previous two. It offers a separate backend for your application without suffering from Cloud Function delays, and it doesn’t force you to write backend code in several front ends. If you’re okay with deploying your own server and you don’t need Firebase SDK’s extra front-end speed, then go ahead with this approach.
Conclusion - Our Recommendation
If you ask us, the best Firebase practice is using both its SDK and Cloud Functions. You don’t need to build your whole application using a single approach. Each one has its own strengths and performs well in specific situations. The hard part is knowing when to use each one. But don’t worry, we’ve figured it out for you.
Use the SDK when you need an immediate response. You can employ it to either write data or retrieve data directly from the database. But you should only use SDK minimally in handling business logic. It works best when acquiring or writing pure data. Any other logic should use Cloud Functions triggered on database writes or updates.
For example, lets’ say you create a shopping order form on the front end. You should use the SDK to write only the data received from the front end, while other logic – like calculating the invoice, assigning an order number, or sending a confirmation email – should use database write-triggered Cloud Functions. Intensive tasks, background jobs, and data caching/export/import jobs that don’t need immediate responses should also be written by the Cloud Functions.
There you have it. Now you don’t need to take a trial-and-error approach to Firebase’s services. Learn from our attempts and if you follow these best practices, you’ll be streamlining your development in no time.