Author's Note: This post was updated on January 31st 2019 to reflect the fact that Cloud Firestore has graduated from Beta to General Availability
Hey, did you hear the big news? We just announced the release of Cloud Firestore -- the new database that lets you easily store and sync app data to the cloud, even in realtime!
Now if you're experiencing some deja vu, you're not alone. We realize this sounds awfully similar to another product you might already be using -- the Firebase Realtime Database. So if you're experiencing some deja vu, you're not alone.
So why did we build another database? And when would you choose one over another? Well, let's talk about what's new and different with Cloud Firestore, and why you might want to use it for your next app.
While our documentation covers all of the differences between the Realtime Database and Cloud Firestore in much more detail, let's look at the main differences between the two products. And we'll start with...
While the Firebase Realtime Database is basically a giant JSON tree where anything goes and lawlessness rules the land1, Cloud Firestore is more structured. Cloud Firestore is a document-model database, which means that all of your data is stored in objects called documents that consist of key-value pairs -- and these values can contain any number of things, from strings to floats to binary data to JSON-y looking objects the team likes to call maps. These documents, in turn, are grouped into collections.
Your Cloud Firestore database will probably consist of a few collections that contain documents that point to subcollections. These subcollections will contain documents that point to other subcollections, and so on.
This new structure gives you several important advantages in being able to query your data.
For starters, all queries are shallow, meaning that you can simply fetch a document without having to fetch all of the data contained in any of the linked subcollections. This means you can store your data hierarchically in a way that makes sense logically without worrying about downloading tons of unnecessary data.
In this example, the document at the top can be fetched without grabbing any of the documents in the subcollections below
Second, Cloud Firestore has more powerful querying capabilities than the Realtime Database. In the Realtime Database, trying to create a query across multiple fields was a lot of work and usually involved denormalizing your data.
For example, imagine you had a list of cities, and you wanted to find a list of all cities in California with a population greater than 500k.
Cities, stored in the Realtime Database
In the Realtime Database, you'd need to conduct this search by creating an explicit "states plus population" field and then running a query sorted on that field.
Creating a combined state_and_population field, just for queries
With Cloud Firestore, this work is no longer necessary. In some cases, Cloud Firestore can automatically search across multiple fields. In other cases, like our cities example, Cloud Firestore will guide you towards automatically building an index required to make these kinds of queries possible…
...and then you can simply search across multiple fields.
Cloud Firestore will automatically maintain this index for you throughout the lifetime of your app. No combo fields required!
While the Realtime Database does scale to meet the needs of many apps, things can start to get difficult when your app becomes really popular, or your dataset gets truly massive.
Cloud Firestore, on the other hand, is built on top of the same Google Cloud infrastructure that powers some pretty popular apps. So it will be able to scale much more easily and to a much greater capacity than the Realtime Database can. While the Realtime Database tops out at about 100,000 concurrent connections, for instance, Cloud Firestore will accept up to 1,000,000 concurrent client connections per database. For a complete list of Cloud Firestore's limits, be sure to visit the documentation.
Cloud Firestore also has a more robust Service Level Agreement than the Realtime Database. Cloud Firestore guarantees 99.999% uptime in multi-region instances (more on that below) and 99.99% uptime in regional instances. The Realtime Database, by contrast, guarantees 99.95% uptime.
And with the new querying structure, all Cloud Firestore queries scale to the size of your result set -- not the size of your data. This means that a search for the top 10 restaurants in Chicago for a restaurant review app will take the same amount of time whether your database has 300 restaurants, 300 thousand or 30 million. As one engineer here likes to put it, "It's basically impossible to create a slow query in Cloud Firstore."
While some developers appreciated the real-time nature of the Realtime Database for building features like chat or enabling magical collaborative experiences, we found that many of our developers simply wanted to use the Realtime Database as a traditional, "Just fetch data when I ask for it" kind of service.
Although the Realtime Database does support this with .once calls, they can sometimes feel a bit unnatural to use and often play second-fiddle to the streaming methods within the SDKs. With Cloud Firestore, making simple one-time fetch queries is much more natural and is built as a primary use case within the Firestore API.
.once
Of course, you can still add support for listeners, so that your clients have the ability to receive updates whenever you data changes in the database. But now you have the flexibility to retrieve your data however you'd like.
Cloud Firestore has support for multi-region locations. This means that your data is automatically copied to multiple geographically separate regions at once. So if some unforeseen disaster were to render a data center -- or even an entire region -- offline, you can rest assured that your data will continue to be served
And for you database aficionados out there, we should point out that Cloud Firestore offers strong consistency (just like Cloud Spanner!), which means that you get the benefits of multi-region support, while also knowing that you'll be getting the latest version of your data whenever you perform a read.
There are currently two different multi-region locations you could use to host your data (one in North America, the other in Europe). And for those of you who don't need the heavy-duty capabilities of a multi-region database, Cloud Firestore also offers several regional instances in locations around the world, most of which will be available at a lower price tier starting in early March, 2019. By contrast, the Realtime Database is only hosted in North America.
The two databases have fairly different pricing models: The Realtime Database primarily determines cost based on the amount of data that's downloaded, as well as the amount of data you have stored on the database.
While Cloud Firestore does charge for these things as well, they are significantly lower than what you would see in the Realtime Database2. Instead, Cloud Firestore's pricing is primarily driven by the number of reads or writes that you perform.
What this means is that if you have a more traditional mobile app where your client is occasionally requesting larger chunks of data from your database -- think something like a news app, a dating app, or a turn-based multiplayer game, for instance -- you will find that Cloud Firestore's pricing model might be more favorable than if you ran the same app on the Realtime Database.
On the other hand, if you have an app that's making very large numbers of reads and writes per second per client (for instance, a group whiteboarding app, where you might be broadcasting everybody's drawing updates to everybody else several times a second), Cloud Firestore will probably be more expensive.3 At least for that portion of your app -- you can always use both databases together, and that's fine, too.
Of course these are just rough guidelines, make sure you check out the Pricing section of our documentation for all the details on Cloud Firestore pricing.
With this list of changes, you might come away with the impression that Cloud Firestore is simply better than the Realtime Database. And while Cloud Firestore does have a fair number of improvements over the Realtime Database, there are still a few situations where you might want to consider using the Realtime Database for some of your data. Specifically…
In general, we recommend that new applications start with Cloud Firestore, unless you think that your app has unique needs, like those we outlined above, that make it more suitable for the Realtime Database.
On the other hand, if you have an existing database that's already running just fine on the Realtime Database, go ahead and keep it there! If you find you're running up against issues where Cloud Firestore could really help you out, then you could consider switching, or moving part of your data to Cloud Firestore and using both databases together. But don't switch just for the sake of switching.
And if you're looking for a magic, "Please convert my database from the Realtime Database to Cloud Firestore" button, there isn't one4! And, frankly, we don't know if there ever will be. Given how different the database, querying, and pricing structures are between the two, blindly converting a database that's been optimized for the Realtime Database over to Cloud Firestore wouldn't necessarily be a great experience. We want you to be more thoughtful about making this kind of change.
If you're interested in giving Cloud Firestore a try, there's a lot of places for you to get started. You can check out the documentation, play around with our sample apps, try our interactive code labs, and maybe watch a getting started video or two.
There's a lot we think you'll be able to do with Cloud Firestore and we're excited to see what kinds of apps you're able to build with it. As always, if you have questions, you can hit us up on any of our support channels, or post questions on Stack Overflow with the google-cloud-firestore and firebase tags. Good luck, and have fun!
google-cloud-firestore and firebase tags
Subject to security rules, of course ↩
Something on the order of 27 times cheaper, in the case of data storage ↩
As an aside, though, I've personally found that the new pricing structure makes it much easier for me to estimate my costs, which is nice. ↩
Although we do have a very handy Migration Guide. ↩
Today we're excited to launch Cloud Firestore, a fully-managed NoSQL document database for mobile and web app development. It's designed to easily store and sync app data at global scale, and it's now available in beta.
Key features of Cloud Firestore include:
And of course, we've aimed for the simplicity and ease-of-use that is always top priority for Firebase, while still making sure that Cloud Firestore can scale to power even the largest apps.
Managing app data is still hard; you have to scale servers, handle intermittent connectivity, and deliver data with low latency.
We've optimized Cloud Firestore for app development, so you can focus on delivering value to your users and shipping better apps, faster. Cloud Firestore:
As you may have guessed from the name, Cloud Firestore was built in close collaboration with the Google Cloud Platform team.
This means it's a fully managed product, built from the ground up to automatically scale. Cloud Firestore is a multi-region replicated database that ensures once data is committed, it's durable even in the face of unexpected disasters. Not only that, but despite being a distributed database, it's also strongly consistent, removing tricky edge cases to make building apps easier regardless of scale.
It also means that delivering a great server-side experience for backend developers is a top priority. We're launching SDKs for Java, Go, Python, and Node.js today, with more languages coming in the future.
Over the last 3 years Firebase has grown to become Google's app development platform; it now has 16 products to build and grow your app. If you've used Firebase before, you know we already offer a database, the Firebase Realtime Database, which helps with some of the challenges listed above.
The Firebase Realtime Database, with its client SDKs and real-time capabilities, is all about making app development faster and easier. Since its launch, it has been adopted by hundred of thousands of developers, and as its adoption grew, so did usage patterns. Developers began using the Realtime Database for more complex data and to build bigger apps, pushing the limits of the JSON data model and the performance of the database at scale. Cloud Firestore is inspired by what developers love most about the Firebase Realtime Database while also addressing its key limitations like data structuring, querying, and scaling.
So, if you're a Firebase Realtime Database user today, we think you'll love Cloud Firestore. However, this does not mean that Cloud Firestore is a drop-in replacement for the Firebase Realtime Database. For some use cases, it may make sense to use the Realtime Database to optimize for cost and latency, and it's also easy to use both databases together. You can read a more in-depth comparison between the two databases here.
We're continuing development on both databases and they'll both be available in our console and documentation.
Cloud Firestore enters public beta starting today. If you're comfortable using a beta product you should give it a spin on your next project! Here are some of the companies and startups who are already building with Cloud Firestore:
Get started by visiting the database tab in your Firebase console. For more details, see the documentation, pricing, code samples, performance limitations during beta, and view our open source iOS and JavaScript SDKs on GitHub.
We can't wait to see what you build and hear what you think of Cloud Firestore!
Here's how it works, in a nutshell. We'll use a Realtime Database trigger as an example.
Imagine you have an existing project with a single function in it called makeUppercase. It doesn't have to be deployed yet, just defined in your index.js:
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original').onCreate(event => { const original = event.data.val() console.log('Uppercasing', event.params.pushId, original) const uppercase = original.toUpperCase() return event.data.ref.parent.child('uppercase').set(uppercase) })
This onCreate database trigger runs when a new message is pushed under /messages with a child called original, and writes back to that message a new child called uppercased with the original value capitalized.
Now, if you can kick off the emulator shell from your command line using the Firebase CLI:
$ cd your_project_dir $ firebase experimental:functions:shell
Then, you'll see something like this:
i functions: Preparing to emulate functions. ✔ functions: makeUppercase firebase>
That firebase prompt is waiting there for you to issue some commands to invoke your makeUppercase function. The documentation for testing database triggers says that you can use the following syntax to invoke the function with incoming data to describe the event:
makeUppercase('foo')
This emulates the trigger of an event that would be generated when a new message object is pushed under /messages that has a child named original with the string value "foo". When you run this command in the shell, it will generate some output at the console like this:
info: User function triggered, starting execution info: Uppercasing pushId1 foo info: Execution took 892 ms, user function completed successfully
Notice that the console log in the function is printed, and it shows that the database path wildcard pushId was automatically assigned the value pushId1 for you. Very convenient! But you can still specify the wildcard values yourself, if you prefer:
makeUppercase('foo', {params: {pushId: 'custom_push_id'}})
After emulating this function, if you look inside the database, you should also see the results of the function on display, with /messages/{pushId}/uppercased set to the uppercased string string value "FOO".
You can simulate any database event this way (onCreate, onDelete, onUpdate, onWrite). Be sure to read the docs to learn how to invoke them each correctly.
In addition to database triggers, you can also emulate HTTPS functions, PubSub functions, Analytics functions, Storage functions, and Auth functions, each with their own special syntax.
The Cloud Functions shell is currently an experimental offering, and as such, you may experience some rough edges. If you encounter a problem, please let us know by filing a bug report. You can also talk to other Cloud Functions users on the Firebase Slack in the #functions channel.
Typing the function invocation each time can be kind of a pain, so be sure to take advantage of the fact that you can navigate and repurpose your invocation history much like you would your shell's command line using the arrow keys.
Also note that the shell is actually a full node REPL that you can use to execute arbitrary JavaScript code and use special REPL commands and keys. This can be useful for scripting some of your test code.
Since you can execute arbitrary code, you can also dynamically load and execute code from other files using the require() function that you're probably already familiar with.
And lastly, if you're like me, and you prefer to use a programmer's editor such as VS Code to write your all JavaScript, you can easily emulate functions by sending code you want to run to the Firebase CLI. This command will run test code from a file redirected through standard input:
$ firebase experimental:functions:shell < tests.js
Happy testing!
One of the most important components of a ridesharing app is keeping everything synced in real-time. Sprynt needed fast and reliable synchronized rider and driver apps, GPS tracking, and ride-request queue management. That's why one of the first features that attracted us to Firebase for this app was the Realtime Database.
We leveraged Firebase's synchronization solution for its speed, as well as the Realtime Database listeners for keeping the system fast and lightweight. In our experience, Firebase excels when dealing with simple data schemas that need real-time communication between clients and server.
Besides the core product requirement of real-time communication, Sprynt needed a platform that could support a fully-featured app. For example: authentication for registering and logging in, notifications to help with rider and driver communication, and an easy-to-use dashboard to help the Sprynt team understand and manage their system.
Firebase has all of these components, which made it a leading candidate and our eventual choice. It provides the ability to quickly set up and scale a backend with authentication, push notifications, custom cloud functions, file storage, and analytics. The dashboards and admin tools also allow us to stay focused on building what matters most: a compelling user experience. Simply put, Firebase let Savvy begin a product like Sprynt quickly without compromise.
For authentication, we turned to Firebase Auth because we wanted to take advantage of the new phone authentication added this year at Google I/O. We were able to quickly build an authentication mechanism that allowed for users to sign up via phone numbers. This feature was an important one for Sprynt, since it streamlined the onboarding process. That's especially important when someone might want to get started with Sprynt in a hurry.
When it came to building in notifications, we used Firebase Cloud Messaging. FCM allowed us to send notifications programmatically, such as when a driver is on the way to a rider. Beyond that, FCM gives Sprynt admins the ability to send out quick one-off messages to their user base through the notifications dashboard. We feel that this functionality will prove invaluable for handling services outages, highlighting new specials from advertisers, or other comparable communication regarding the Sprynt service.
Sprynt launched to great success. In the first month of service, they delivered around 5,000 passengers in their pilot service area. The app maintains a 5-star rating and their advertisers are very happy with their results so far.
Sprynt is already pushing hard to keep up with demand from riders and advertisers, as well as the influx of new driver applications. They also have already begun building a steady, repeat ridership base. Google Analytics for Firebase has proven helpful in tracking this kind of usage, as well as version update adoption rates, user device types, and custom events.
We built Sprynt using Firebase for long-term sustainability without constant developer involvement. By leveraging the Firebase console, we made it as easy as possible for Sprynt's team to manage their business, with as little development support as needed. Cloud Storage for Firebase plus Cloud Functions for Firebase allow Sprynt to upload and process updated or new service areas without directly editing the database. These features will become even more important as Sprynt continues to grow in popularity and open new service areas.
While Firebase Realtime Database has some weaknesses in its query support — particularly around complex queries that include filtering and sorting collections — overall, we've been happy with the platform and its progress.
We've used Firebase since it launched years ago, but we continue to appreciate when the observeSingleEventOfType function on one device responds to an event triggered by another. Watching it happen for the first time between the Sprynt Rider app and Sprynt Driver app still provides that "aha" moment, even today.
Firebase continues to enhance our ability to build and scale new businesses as quickly as possible.
If you want to learn more about using Firebase yourself, check out the use cases section of the website or subscribe to the Firebase channel on YouTube.
For many years, developers and app teams have relied on Crashlytics to improve their app stability. By now, you're probably familiar with the main parts of the Crashlytics UI; perhaps you even glance at crash-free users, crash-free sessions, and the issues list multiple times a day (you wouldn't be the only one!).
In this post, we want to share 7 pro-tips that will help you get even more value out of Crashlytics, which is now part of the new Fabric dashboard, so you can track, prioritize, and solve issues faster.
In July, we officially released crash insights out of beta. Crash insights helps you understand your crashes better by giving you more context and clarity on why those crashes occurred. When you see a green lightning bolt appear next to an issue in your issues list, click on it to see potential root causes and troubleshooting resources.
Debugging and troubleshooting crashes is time-consuming, hard work. As developers ourselves, we understand the urge to sign-off and return to more exciting tasks (like building new app features) as soon you resolve a pesky issue - but don't forget to mark this issue as "closed" in Crashlytics! When you formally close out an issue, you get enhanced visibility into that issue's lifecycle through regression detection. Regression detection alerts you when a previously closed issue reoccurs in a new app version, which is a signal that something else may be awry and you should pay close attention to it.
As a general rule of thumb, you should close issues so you can monitor regression. However, you can also close and lock issues that you don't want to be notified about because you're unlikely to fix or prioritize them. These could be low-impact, obscure bugs or issues that are beyond your control because the problem isn't in your code. To keep these issues out of view and declutter your Crashlytics charts, you can close and lock them. By taking advantage of this "ignore functionality", you can fine tune your stability page so only critical information that needs action bubbles up to the top.
Sometimes, you may have multiple builds of the same version. These build versions start with the same number, but the tail end contains a unique identifier (such as 9.12 (123), 9.12 (124), 9.12 (125), etc). If you want to see crashes for all of these versions, don't manually type them into the search bar. Instead, use a wildcard to group similar versions together much faster. You can do this by simply adding a star (aka. an asterisk) at the end of your version prefix (i.e. 9.12*). For example, if you use APK Splits on Android, a wildcard build will quickly show you crashes for the combined set of builds.
As a developer, you probably deploy a handful of builds each day. As a development team, that number can shoot up to tens or hundreds of builds. The speed and agility with which mobile teams ship is impressive and awesome. But you know what's not awesome? Wasting time having to comb through your numerous builds to find the one (or two, or three, etc.) that matter the most. That's why Crashlytics allows you to "pin" key builds so that they appear at the top of your builds list. Pinned builds allow you to find your most important builds faster and keep them front and center, for as long as you need. Plus, this feature makes it easier to collaborate with your teammates on fixing crashes because pinned builds will automatically appear at the top of their builds list too.
Stability issues can pop up anytime - even when you're away from your workstation. Crashlytics intelligently monitors your builds to check if one issue has caused a statistically significant number of crashes. If so, we'll let you know if you need to ship a hot fix of your app via a velocity alert. Velocity alerts are proactive alerts that appear right in your crash reporting dashboard when an issue suddenly increases in severity or impact. We'll send you an email too, but you should also install the Fabric mobile app, which will send you a push notification so you can stay in the loop even on the go. Keep an eye out for velocity alerts and you'll never miss a critical crash, no matter where you are!
The Crashlytics SDK lets you instrument logs, keys, non-fatals, and custom events, which provide additional information and context on why a crash occurred and what happened leading up to it. However, logs, keys, non-fatals, and custom events are designed to track different things so let's review the right way to use them.
Logs: You should instrument logs to gather important information about user activity before a crash. This could be user behavior (ex. user went to download screen, clicked on download button) to details about the user's action (ex. image downloaded, image downloaded from). Basically, logs are breadcrumbs that show you what happened prior to a crash. When a crash occurs, we take the contents of the log and attach it to the crash to help you debug faster. Here are instructions for instrumenting logs for iOS, Android, and Unity apps.
Keys: Keys are key value pairs, which provide a snapshot of information at one point in time. Unlike logs, which record a timeline of activity, keys record the last known value and change over time. Since keys are overwritten, you should use keys for something that you would only want the last known value for. For example, use keys to track the last level a user completed, the last step a user completed in a wizard, what image the user looked at last, and what the last custom settings configuration was. Keys are also helpful in providing a summary or "roll-up" of information. For instance, if your log shows "login, retry, retry, retry" your key would show "retry count: 3." To set up keys, follow these instructions for iOS, Android, and Unity apps.
Non-fatals: While Crashlytics captures crashes automatically, you can also record non-fatal events. Non-fatal events mean that your app is experiencing an error, but not actually crashing.
For example, a good scenario to log a non-fatal is if your app has deep links, but fails to navigate to them. A broken link isn't something that will necessarily crash your app, but it's something you'd want to track so you can fix the link. A bad scenario to log a non-fatal is if an image fails to load in your app due to a network failure because this isn't actionable or specific.
You should set up non-fatal events for something you want the stack trace for so you can triage and troubleshoot the issue.
If you simply want to count the number of times something happens (and don't need the stack trace), we'd recommend checking out custom events.
These 7 tips will help you get the most out of Crashlytics. If you have other pro-tips that have helped you improve your app stability with Crashlytics, tweet them at us! We can't wait to learn more about how you use Crashlytics.
Get Crashlytics