13 features I wish Firebase had
Tags: firebase, serverless, jamstack, googlecloud
Published: 2022-01-25 14:32:24

I love [Firebase](https://firebase.google.com/). I love how quickly it allows me to develop a new product without having to worry about infrastructure. I feel like Firebase is a dream for indie developers.

However, Firebase isn't perfect. There are some important features I wish they would work on. Some of those are now handled by products such as [PlanetScale](https://planetscale.com/) and [Xata](https://www.xata.io/).

But I love using Firebase. I think they have the potential to really be a BaaS (Backend-as-a-Service), providing everything you need to run a backend without having to worry about infrastructure and scale.

Yesterday, [Michael Bleigh](https://twitter.com/mbleigh) from Firebase, asked this on Twitter:

{% twitter 1485665341439033345 %}

So, I've decided to write this post in response with the most important features I wish Firebase would have right now.

## 1. Full-text Search

I don't think I ever worked on a project where I didn't need full-text search at some point. We usually end up having to use something like [Elastic](https://www.elastic.co/app-search/) or [Algolia](https://www.algolia.com/). They're great services and [Firebase even recommend them](https://firebase.google.com/docs/firestore/solutions/search) but it would be great if full-text search would be included in their SDK, at least for Firestore.

I hope one day we can simply run a query like this:

```ts
const postsRef = collection(db, 'posts');
const query = await searchCollection(postsRef, 'da vinci');
```

That query would return all posts where the word `da vinci` is mentioned based on a ranking that we could define using a configuration file (`e.g. firestore.search.json`):

```json
"posts": {
  "priority": ['title', 'content', 'author']
}
```

We could also override the priority when we run our query by specifying which fields we want to search on:

```ts
const postsRef = collection(db, 'posts');
const query = await searchCollection(postsRef, 'da vinci', ['author']);
```

The query above would run a full-text search on the `author` property only.

## 2. Aggregation queries

When I need data aggregation I either use Cloud Functions (for simpler aggregations) or I don't use Firebase at all. I know data aggregation is hard to accomplish on Firestore but it would be a game-changer for their product if they manage to do it.

I'd love to see queries like these:

```ts
const postsRef = collection(db, 'posts');
const queryRef = query(postsRef, where('author', '==', 'davinci'));
const postsCount = await count(queryRef); // 242
```

Where I count the number of documents in a given collection based on a specific query. The query above, for example, would return the number of posts a specific user has published.

I'd love to see similar queries for other data aggregations such as `sum`, `average`, `min`, `max`, etc. For example, a few years ago I was working on this IoT application where we needed to display real-time aggregated data for energy consumption. We weren't using Firebase for that but, given Firebase's real-time capabilities, it would have been amazing to use it if it would support data aggregation like this:

```ts
const consumptionRef = collection(db, 'consumption');

const queryRef = query(
  consumptionRef,
  where('customerID', '==', 'uid')
  where('createdAt', '>=', '2021-01-01')
  where('createdAt', '<=', '2021-01-31')
  groupBy('hour')
);

const consumption = await sum(query, 'kwh');
```

The query above would sum all values from the `kwh` field grouped by hour based on the `createdAt` property. It would return something like this:

```json
[{
  "date": 2021-01-01 00:00:00,
  "kwh": 0.05
}, {
  "date": 2021-01-01 01:00:00,
  "kwh": 0.04
}, {
  "date": 2021-01-01 02:00:00,
  "kwh": 0.03
}, { ... }]
```

In theory, I'm already able to accomplish something similar to that using Cloud Functions where I'd have an `onWrite` trigger for the `consumption` collection and it would update a `_dataAggregation/{collectionName}/{consumerID}/{dateGroup}` document (i.e. `_dataAggregation/consumption/123/2021_01_01_01_00_00`). But that's too much work, so I don't use Firebase when I need that kind of aggregation.

However, I'd love if Firestore would allow us to setup data aggregations similar to how we're able to have indexes. We could have a `firestore.aggregation.json` file like this:

```json
[{
  "collectionName": "consumption",
  "operation: "sum",
  "kind": { "type": "date", "field": "createdAt" },
  "groupBy": ["hour", "day", "month", "year"],
  "filters": ["customerID", "roomID"],
  "field": "kwh"
}]
```

When we deploy a new aggregation file, Firestore would automatically create those aggregations and watch for changes in the specified documents/fields to update the aggregation - similar to how we'd do this using Cloud Functions but automatically.

## 3. Detailed usage logs

Sometime ago I ran into an issue where my Firestore bill had a spike but I didn't see an increase in traffic. Debugging that was really painful. The spike was coming from the number of reads. Initially, I thought I was suffering an attack (we didn't have [AppCheck](https://firebase.google.com/docs/app-check) back then) but that wasn't the case. It turns out, I had a Cloud Function that was reading (extremely) often from a collection.

My life would have been much easier if Firebase would provide detailed logs of reads/writes/deletes for each document. [Key Visualizer](https://cloud.google.com/firestore/docs/key-visualizer) may help with this nowadays but it would be amazing to have easily accessible logs from the Firebase Console. For example:

- Go to the "Usage" tab on Firestore.
- Select "Reads", "Writes", or "Deletes".
- Group by "collections" or "documents".
- Order then by ascending or descending.

## 4. Joins using references

Firestore has a [Reference data type](https://firebase.google.com/docs/firestore/manage-data/data-types#data_types) but it isn't very useful at the moment. I wish we could use References to automatically have joins.

For example, let's say we create the following post in our database:

```ts
const post = {
  author: doc(db, 'users', user.uid),
  content: 'whatever',
  createdAt: serverTimestamp(),
  title: 'hello world!'
};
```

I know Firebase isn't a relational database but I wish it would automatically create a relation between the `author` field and its reference. So, when I'd fetch this post, I could do `author.name` to get the author name, for example.

We can do this using Cloud Functions and adding a `authorData` field and keep it in sync with `author/{authorID}` but it would amazing if Firestore would automatically do this for us.

In their backend, they could have a trigger that automatically fetches the author document when the post is created and they could automatically update the author data when `users/{userID}` changes. This way our queries would still be fast and cheap but we wouldn't have to handle this logic by ourselves.

## 5. Automatic backups for Firestore

The official [Firestore documentation has a tutorial](https://firebase.google.com/docs/firestore/solutions/schedule-export) on how to backup your Firestore database periodically. But I wish they would do backups automatically, at least on a daily basis, and provide an one-click option in the console to restore (or download) a backup.

## 6. Data migration

Doing data migrations on Firestore can be painful. I wish Firebase would provide an official tool for handling that. Something that we could call from the CLI:

```sh
# Create a new /migrations/2022_01_20_10_28_54-rename-post-author.js file
firebase migrate new rename-post-author

# Run pending migrations
firebase migrate

# Run a specific migration
firebase migrate up 2022_01_20_10_28_54-rename-post-author.ts

# Undo a migration
firebase migrate down 2022_01_20_10_28_54-rename-post-author.ts
```

Migration files would need to have `up` and `down` functions:

```ts
const postsRef = db.collection('posts');

async function up() {
  const posts = await postsRef.get();
  const batch = db.batch();
  
  // Rename post author for each post
  posts.forEach((post) => {
    const data = post.data();

    const updates = {
      author: data.user,
      user: deleteField()
    };

    batch.update(post.ref, updates);
  });

  return batch.commit();  
}

async function down() {}
```

## 7. Migration branches

Databases such as [PlanetScale](https://planetscale.com/) and [Xata](https://www.xata.io/) are using version control for data migrations. It's easier to update your data structure without breaking anything in production. I wish Firebase would have that feature too.

We could use the Firebase Migrate tool I suggested on the item above to create new branches:

```sh
# Run the migration on a new branch
firebase migrate -b rename-post-author

# Create a merge request to merge our feature branch into main 
firebase migrate -mr rename-post-author main

# Interactive panel to list all merge requests and merge them
firebase migrate -lmr
```

## 8. SSR Hosting deployed to the edge

Hosting services like [Vercel](https://vercel.com/), [Fly.io](https://fly.io/), and [CloudFlare Workers](https://workers.cloudflare.com/) allow you to deploy both static files and server-side code close to your users (the edge). I wish Firebase Hosting would also allow us to do it.

Right now, Firebase Hosting only allows us to deploy static files. If we need server-side rendering, then we need to use Cloud Functions on top of it, which adds complexity and it has the cold starts issue.

I wish Firebase Hosting would allow us to deploy server-side code to the edge without using Cloud Functions. It would be another step to use only Firebase for a full-stack application.

## 9. Custom error messages for Security Rules

When a security rule fails, we get a `Permission denied` error from Firestore. I remember reading somewhere they do this for security rules because they don't want users to know which security rule failed.

However, sometimes it's useful to show users a specific validation failed. I wish Firebase would allow us to write custom error messages for each security rule. For example:

```yml
match /posts/{postID} {
  allow create: if
    custom({
      rule: request.resource.data.description.size() < 1000,
      message: 'The post description needs to have less than 1000 characters.'
    })
}
```

This would allow us to use fewer client-side validations and rely on the error messages coming from the backend (Firestore).

## 10. Deploy Firestore to the edge

When we create a new Firebase project, we need to choose which region our GCP resources will live in. That includes where our Firestore database will be located. That's not ideal for global services because some requests will be far away from users, adding latency.

It would be amazing if Firestore would be deployed to the edge (close to users).

## 11. JSON import/export for the Firestore Emulator

The Firestore Emulator allows us to import/export but it does so in its own format. Sometimes, it's useful to fetch some initial data (ex. working locally, testing, etc.). It would be great if the `--import` flag could accept a `json` file to import the data.

## 12. Support indexes in the emulator

I wish I could use more the Firebase Emulator but it's hard to trust it when there are unsupported features such as indexes. I wish Firebase would pay more attention to this and only release new features when it's also available in the emulator.

Otherwise, the emulator doesn't give us confidence that things will be working in the same way as they will in production. I had an issue a few times where I worked on a feature and only found out it was broken after it was already merged to our `staging` environment where I'd get a `missing index` error and I'd need to open a new PR to fix it.

There's an [open issue for this on GitHub](https://github.com/firebase/firebase-tools/issues/2027), though.

## 13. Self-hosted / open-source

Even though I love using Firebase, it's hard to convince larger teams to use it. The main issue people argue about is because Firebase isn't open-source and it would lock us into their product.

If Firebase products were open-sourced and allow us to self-host them, it would be much easier to convince larger teams (especially in enterprise) to adopt their products. Most of the time, I don't even think we would self-host Firebase but making it open-source adds transparency to the process and it's an ensure that we could do it in case things change or Google eventually shuts Firebase down.

## Additional notes

I know there are workarounds to implement some of the functionality above but the user experience isn’t great and they require a lot of work. I wish Firebase would become a backend-as-a-service that allows you to not worry about none of the things above, so you can focus on your product only.

I also know some of those features are best handled by SQL databases but, then, SQL comes with its own challenges (don't need to do SQLsplaining to me). Some of them are being resolved by products like [PlanetScale](https://planetscale.com/) and [Xata](https://www.xata.io/), though. I think the product that manages to solve those issues will have a huge business in their hands, especially with the rise of [Jamstack](https://jamstack.wtf/).

---

[Follow me on Twitter](https://twitter.com/ceolinwill)