I've been using Firebase and, more precisely, Firestore for about five years now. It all began with a school project where we had to build a mobile application that queries data and a manager to handle those data. You can check the code of the application and the manager (I didn't change anything on the code, it's a mess).
I remember being impressed with the ease of implementation. We were able to get and write data to the cloud in less than 2 hours. It was possible to see the updates on the data in live and have a UI that changed accordingly.
I worked on many others projects where we used Firestore as our database. The product is excellent even tho he has a slow development cycle. With experience, I started to see some limitations that bother me.
A quick disclaimer before going any further in the article. The goal of this article is not to argue whether relational or non-relational databases are better. There are use cases where one is preferred over another. Besides, I want to share the experience I have with Firestore and give you some insights. There might be some errors. If that's the case, please leave a comment or send me an email. I'll be more than happy to revisit the article with your feedback.
Where Firestore Shines
Before starting to list the things that annoy me, I want to say that there are times where Firestore is great. I won't get into too many details since it's not the focus of this article, but here are several use cases where I can recommend Firestore:
- When cost is a concern: the free tier of Firestore is quite generous, and it's possible to launch a product without worrying about costs.
- When time is a concern: when building a quick MVP, Firestore is perfect since it allows developers to focus on elements that aren't back-end related. There is no need to develop CRUD endpoints since the SDK handles much of the work.
- Truly unstructured data: there are times where the data is unstructured or has little structure. This could be the case for a chat; for example, Firestore could store the different messages people are exchanging.
- Multi-platform project: one of the strengths of Firestore is its SDKs that are available on every platform. This is a significant advantage for projects built using different technologies since the SDK will provide some protection and consistency.
- Integration with Google Cloud: using Firestore is only one part of Google Cloud. Many other tools are offered to developers. It's possible to analyze a large quantity of Firestore data with Big Query and display those results on a Google Data Studio.
Both of those use cases have their limits since, at one point, migrating to another solution might be required. The development team must define soon enough a strategy to smooth the transition. I think that every team that has worked with Firestore has encountered one of the following problems.
Where are Firestore's Limitation
Data Is Relational
Firestore is a document-oriented NoSQL database. Data are stored in collections that are composed of documents. Those documents can have sub-collections to store other data.
This works fine in some context, but I cannot remember a project where I had data that wasn't relational. Most of the information I had to store was tied to its creator or to another thing stored in the database.
Having this kind of architecture works fine when there is a limited number of collections and fields. However, things start to get complicated when one document has 5-10 relations to other elements.
I was confronted with this issue multiple times while using Firestore. I even thought of duplicating the data across various documents to better perform, which opens too many problems. Having a relational database would have made my life easier and helped me avoid long and unoptimized query chains.
When developing software with Firestore, the only elements that tell the developer the data structure are the models or the classes. There isn't any protection on the Firestore side to ensure that the data are correct and in the proper format.
When working with Firestore, we cannot ensure that everything will be how we want it to be. A developer may send a boolean as a string when updating a document causing many issues on the front-end. It's possible to have some protection when using TypeScript. However, this is still not a magic bullet. Data can be written in any way, shape, or form to Firestore, making the application crash when queried.
On top of this issue, performing data migration is at the developer's charge. There is nothing the enforce the migration or raise an error if a new field is written. The bigger the project, the harder it will be to maintain a clean database. Old data might cause a crash if the migration wasn't done correctly.
Google provides an SDK that handles most of the CRUD operations. It ensures that no garbage is sent to Firestore while giving many liberties to the developer.
The SDK works fine for basic applications. The story is different when data starts to get complex or when manipulation is required. For example, there is no count method, so building a dashboard is complicated and won't be very performant. Lacking basic methods means that computation must be done on the client, and more data must be fetched. This makes little sense when all we want to display is a simple number.
There are solutions to overcome this limitation, for example, having a Cloud Function that increments a number when data is added. However, the results in more code that must be maintained by the developers.
No Server Validation
Firebase is a server-less solution. This means that everything is handled by Google, and developers only focus on building the UI. Firestore SDK doesn't offer a way to validate data. It's not possible, for example, to map a model to a collection to ensure that the sent data is correct.
Insufficient server-side validation can be critical for some projects. It could be possible to use a Cloud Function that will validate data before sorting it on Firestore, but this completely defeats the purpose of the SDK. There is no real workaround for this problem.
It's simple if you want to use Firestore, you won't validate your data. Everything is handled in the front-end whether you like it or not.
No Native Backup Solution
By default, Firestore offers no backup. It's up to the developers to write some script that will save the data. Having no backup is a real threat to the business since any mistake made could have catastrophic results. Developers could wipe the entire production database if they make a mistake in the migration script.
Google offers a way to export the database, but it cannot be automated. Developers can still write a Cloud Function that automatically runs and saves data to a storage bucket.
Not having a native backup solution is terrible. This forces developers to write their own backup script and must be done for every project.
Google may release a native backup solution since something exists for real-time databases. It's a matter of time to have something for Firestore, but it should already exist.
There is no doubt that Firebase is highly scalable and that the Google team developed a robust solution. I never had the chance to work on a project with thousands of concurring users online, so I can't speak from experiences. That being said, I know that having a scalable architecture is essential.
However, Firestore isn't scalable and will gradually cost more money. I'm not referring to the cost of using Firestore but the costs of maintaining it. In the long run, using Firestore will require more and more developer time because of the limitation detailed above.
Using Firestore as a database will become more and more costly because the development team will either maintain the data with migration scripts and checks or implement error protections in the code.
That's why, although Firestore is technically scalable, I don't think its use is. Choosing this database for an MVP is great and speeds the development time, but using it isn't suited in the long run.
Is Firestore Recommended?
Google provides some uses cases for Firebase. Firestore is recommended for simple features added in an application rather than a fully-fledged database solution. Google explains how Firestore could be used for a user profile or a real-time inventory.
There is no mention of Firestore used as the sole database for a whole project. This might be done intentionally by Google because they want developers to use the Real-Time Database the offer.
What Are the Alternatives
It would make no sense to write an article showing some weaknesses of Firestore without proposing alternatives.
The first solution that comes to mind is Supabase which sees itself as an open-source replacement for Firestore. Superbase offers an SDK, supports live data updates, and will soon support cloud functions. This solution is attractive because the data is stored in a PostgreSQL database. A future article will undoubtedly be dedicated to this solution.
It is also possible to talk about solutions that require more work to be set up but are very efficient. For example, Django or Laravel allows creating powerful back-end used by many services. Comparing Firestore and these services is not totally fair because they are not similar. It is, however, possible to do without Google and use Django or Laravel as a database storage solution. That's why they are mentioned anyway.
The purpose of this article is not to trash Firestore. It is an excellent product that allows for rapid prototyping. There are many cases where Firestore makes sense. However, it is not a universal solution, and there are some points to consider before deciding to use this solution in an application. It also showcases alternatives such as Supabase that could be better suited for some projects.