I recently watched I tried 5 Firebase alternatives (from Fireship). I have thoughts on this same subject, but from a slightly different perspective.
I do Cloud Native Development and have built applications utilizing three of the BaaS solutions discussed in the video - Google Firebase, AWS Amplify and Supabase. With that said, today, I typically create applications directly in AWS and do not use any of the BaaS solutions. What follows are my thoughts on the three BaaS solutions I have used and a little about why I tend to stay away from them.
Disclaimer - it has been a little while since I spent a lot of time with Google Firebase and AWS Amplify so some of my take may be a little out of date.
My Main Issues with BaaS Solutions
Solution Lock In / Tight Coupling / Lack of Flexibility / Lack of Portability
If there is one main reason I stay away from the BaaS solutions it is to avoid solution lock in. None of the BaaS providers do a particularly good job of letting you build an application that doesn’t completely rely on their solution.
When I build an application I try to decouple as much of it as I can from the platform it runs on. This is one of the changes of Cloud Native Development. Achieving a level of decoupling leaves me options in the future for where the application is deployed.
The BaaS solutions typically start with encouraging (pushing, requiring) you to use their client library to interact with their backend services. In some cases you have options, I will discuss this more with the individual solutions, but the options are limited. This means you cannot easily decouple your solution from their platform and it also makes it more difficult to decouple your frontend and backend.
Another area where you can get locked in is around authentication and authorization. In particular, the way you manage user permissions tends to be proprietary to the BaaS solution and is not easily portable down the road.
I do most of my Cloud Native Development on AWS today. You might be thinking that I’m locking myself into AWS as a vendor, why is that different from the BaaS solution?. The answer to that is a bit complicated but with AWS I’m defining the services I use and how I use them which allows me flexibility in how I construct an application. This provides a bit more flexibility. However, make no mistake, that applications I create on AWS are not runnable anywhere else but I can, and do, create reasonable abstractions that make it possible to move from one platform to another with some effort.
Let me illustrate some of this with two real world examples.
The first example is a hotel digital media library application that I built on Firebase. The application was the subject of a series of blog posts on this site several years ago. I recently started thinking about porting the solution to AWS. Every single part of the solution would need to be updated. In the frontend I would need to change the libraries that are used to access backend services. This would probably lead to deeper changes based on new responses from the new backend. The backend services would obviously change and I would need to port all of the associated data. User permissions are specific to Google Firestore and would need to change. The things that might survive are some amount of the UI and some of the function code that was written to process images. This is the level of wholesale change I try to prevent when I build Cloud Native applications today.
The second example is a recent application that started on Supabase and moved to AWS. One of the parts of Supabase I like is that you can call (most of) your database and authentication via a REST API Supabase exposes; which is how I integrated the backend and frontend in the application. When I decided to port the application to AWS I rewrote the backend and I only had to make minor changes to how I was using the API; changing the API URL and to how some of the requests were constructed (the Supabase REST API is a little quirky, more on this below). I was even able to continue using the models I had defined for the API because I exposed the same data from AWS. In this case, the database changed from SQL (Supabase Postgres) to NoSQL (AWS DynamoDB) without the frontend application being any the wiser. It only took a couple days to port the whole thing and I had a high degree of confidence the application was still working. This is the type of thing I do more of today to future proof the Cloud Native applications I build today.
It is worth noting that locking in on one solution is not totally bad, it can have a benefit. If you are not interested in having more options for deploying your solution elsewhere and you lock in to one solution you can typically build a smaller, simpler solution that may end up being easier to support. The hotel media library I referenced in the example above has continued to work in Firebase without issue for several years.
Multiple Environments / Infrastructure-as-Code
The other big thing that has changed for me over time is more and better use of Infrastructure-as-Code (IaC). This is never a top tier feature or discussion point for BaaS solutions. When you get started defining your backend services it is tempting to use the console to get exactly what you need as quickly as possible (the BaaS solutions don’t discourage this). However, you will quickly run into a challenge. It is difficult (impossible) to create another exact copy of your environment. You need easily duplicated environments for two very important reasons. One, you can give each developer their own environment so they don’t run into one another. Two, you can deploy a production environment while working on new features in another environment.
This probably sounds a bit rudimentary to most folks at this point but then why don’t the BaaS solutions take this a bit more seriously? This was an ongoing challenge with AWS Amplify for a long time (might be better now). Supabase mentions this in an article that discusses you building smart deployment scripts to support this. I have seen references to this in the Google Firebase docs but I also remember doing a bunch of manual duplication in the past (again, this may not be the case anymore).
Having the ability to create isolated environments in or across multiple AWS accounts is a foundational part of how I build applications today and I intentionally choose tools that make this easy.
Thoughts on Specific BaaS Solutions
Google Firebase
As discussed above, I have built one application on Firebase (media library) that also leverages some bits from Google Cloud. I have considered it for other projects but ultimately have ended up staying away. Most of my work is web applications. If I did more mobile development I might feel differently about Firebase. I do think it is particularly strong for mobile development.
My general impression is that Google Firebase is a solid solution. I don’t think there is any doubt that it is the dominant player in the BaaS solutions space. It is interesting that it started as an acquisition by Google as opposed to being something spun out of Google Cloud. Over time I believe Firebase has grown closer to Google Cloud but has largely existed separately. This differs quite a bit from how AWS Amplify and Supabase have come to be (more on that follows).
One of the things I really like about this relationship between Google Cloud and Firebase is how Firebase exposes simplified services, while leaving you the option to step up to Google Cloud services when required. I think this was likely an intentional strategy from Google. The best example of where this shines is Authentication. Firebase Authentication is quite straightforward. If you compare this to AWS Amplify where they expose AWS Cognito it couldn’t be more different. Cognito has so many options and can be quite overwhelming when you are trying to wrap your head around how to use it in an application.
The ability to leverage Google Cloud services in Firebase also lets an application grow when and where needed. For example, in the media library application I leverage Vision AI to pull more information from images in the library. This breadth of service is something that a small vendor like Supabase cannot compete with.
The miss with Firebase for me is the lack of tools to help separate the frontend and backend via API. There may be ways to use Functions to achieve this but it doesn’t seem like something that Firebase promotes or recommends.
Likes:
- Rock solid
- Good lineup of supported services - really good for mobile
- Simplified solutions
- Ability to incorporate Google Cloud services
Dislikes:
- No real API solution for better flexibility / portability
AWS Amplify
In the past I have had a particular interest in AWS Amplify. To that end I was a co-founder of the AWS Amplify Meetup in Toronto - pre-pandemic. Even with that, I have only used Amplify on two production grade projects. I have used it a few more times for prototyping or proof of concepts. I generally and intentionally choose not to use Amplify when building applications on AWS today.
AWS Amplify is an interesting solution. It does seem that it came about as AWS’s attempt to compete with Google Firebase but it does things differently. As opposed to building specific solutions for developers building applications, AWS Amplify, attempts to provision full AWS services in a simplified way that makes them more easily used by application developers. When this works, it works okay, when it doesn’t work it makes for an environment that can be tricky to troubleshoot. Sometimes it feels like there is a bit too much mystery in what Amplify is doing under the covers. One of the side-effects (benefits?) of Amplify implementing AWS services directly means you are going to get to know the underlying AWS services (even if you don’t want to).
I would speculate that Amplify’s attempt to catch a leading rival has come with some growing pains. Amplify has a bit of a history of introducing breaking changes from build to build. That is, when you upgrade Amplify and deploy your solution you may find things that no longer work.
Amplify also comes with some ‘interesting’ solution choices - like implementing a GraphQL API on top of AWS DynamoDB. For those who don’t know DynamoDB, it is a NoSQL database that exposes two keys that can be used for queries. If you don’t know GraphQL, it is the API that allows queries to be coded into API requests. That has always felt like an odd combination to me. It leads to a solution that ends up doing a lot of table scans and filtering
Also, the Amplify codegen creates a new DynamoDB table for each GraphQL schema which can lead to a lot of DynamoDB tables. This feels like another strange choice when another part of AWS preaches and extols the virtue of single-table design with DynamoDB. On one project I worked on we hit the DynamoDB table limit for a Region in an AWS Account - it is a quick ticket with support to adjust this but probably shouldn’t happen.
Historically, Amplify has been a bit rough to use in team environments. They have attempted to improve this over time.
One of the things I really like about Amplify is that they leverage APIs to separate the frontend and backend (GraphQL and/or REST). However, this has some challenges. First, you define your backend by running CLI commands in the frontend - this creates some weird coupling. Also, you are encouraged (pushed) to use the AWS Amplify client as your library to use the APIs that get created. This also creates a weird coupling, and it isn’t actually necessary - you can use other API clients if you prefer.
I feel like I have beat up Amplify a little bit here - that wasn’t intentional. It is a really great solution for getting an application running as quickly as possible. Also, through the Meetup in Toronto, we met and had a couple AWS team members come and speak and they are solid, super smart folks.
Likes:
- Fast to prototype solutions
- Use of production quality AWS services
- Decent learning path to learn more about specific AWS services
- API separation of frontend and backend
Dislikes:
- Sometimes hard to follow or modify how AWS services are deployed and configured
- Implements anti-patterns
- History of being brittle - breaking changes
- Hard to use in a team environment - too many objects, too slow
Supabase
Supabase is a YCombinator startup that has received a tremendous amount of early funding. For some reason Supabase likes to market itself as being ‘open source’. I don’t really get why it would be important that a service is running on an open source platform, unless this the story is about portability and I don’t think it is - I’m just looking for the service.
The thing that is really great about Supabase is that it provides easy access to create SQL databases. This is not super easy, or even possible, with Firebase or Amplify (Amplify does offer some level of support with Aurora - the last/first time I tried it, it wasn’t great). They both opt for NoSQL databases by default.
The other thing I like about Supabase is that they do expose a lot of what they offer via a prebuilt REST API which offers some portability (I discussed this above). Some of the REST calls look a little weird but the responses are good, it is just the way you construct requests that can be a little weird. Also, it is probably worth noting that you don’t have a lot of flexibility with this prebuilt API. If you want more elaborate requests than what is presented you are probably going to have to do something with Stored Procedures or Functions.
Probably the biggest hurdle for Supabase is the lack of services. They provide many of the basic services but lack the breadth of portfolio from Google or AWS. I am a bit surprised that Supabase has stayed away from providing somewhere to host a web application. So, if you go with Supabase you will be looking for another provider (maybe someone like Netlify or Vercel) to host the frontend of your web application.
One of things that is interesting about Supabase is that it runs on AWS. So, don’t choose Supabase because you want to avoid AWS (side note, I think there is a lot more Cloud on Cloud out there than people realize).
Likes:
- SQL
- A decent amount of REST support
Dislikes:
- Cannot easily create different environments
- No hosting for the application itself (limited services in general)
- The REST API is okay but I would consider it a little non-standard and not flexible
BaaS Solution Conclusions
Firebase, in particular, feels like a perfectly reasonable production application solution if there is no compelling reason to think about portability.
I might occasionally use Amplify or Supabase for some quick prototyping but even that is tough to justify. It doesn’t save me very much time on the prototype and it costs me time as soon as the prototype moves forward to anything like a proof of concept.
Supabase might have a home in my toolkit for when I need a quick SQL database (and that need does come up from time to time) for something non-production.
If you want to see more about how I build Cloud Native Applications stay tuned, I will be posting more on that soon.