In this tutorial you will learn how to build an Ionic app that stores data in a Firebase Database. We will explore in detail how to implement all the four CRUD operations using the Firebase Cloud Firestore database.

You might ask yourself "What is the best database to use in my Ionic project?" and the truth is that, as always in software, it depends.

There are a variety of options available for storing data, and choosing the right one will depend on your application needs, your expertise, and resources.

Firebase offers Cloud Firestore which is a flexible, scalable NoSQL cloud database that is very easy to use with an Ionic app.

Although this tutorial is about firebase database, I want to mention that there are many other DB options that you can use such as:

SQLite: It provides a self-contained, serverless, zero-configuration, transactional SQL database engine for mobile and desktop applications.

Couchbase Lite: A full-featured embedded NoSQL database for apps that run on mobile, desktop, and embedded devices.

AWS Amplify: A comprehensive library for building sophisticated cloud-powered apps. It includes a JavaScript library with support for Ionic.

MongoDB: As a document NoSQL database, MongoDB makes it easy for developers to store structured or unstructured data. It uses a JSON-like format to store documents. This format directly maps to native objects in most modern programming languages. In Build a complete mobile app with Ionic Framework we used Mongo and NestJS to build the demo app.

PostgreSQL: is a powerful, open source object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance.

This tutorial explains all the steps needed in order to set up a Firestore database and connect it with your Ionic application in order to save and fetch data.

If you are looking for an Ionic Starter App with Firestore integration ready to go, you should check this Ionic Firebase Template. It includes many examples and use cases of data handling using Ionic and Firebase.

Firebase offers a set of tools that help in the process of building and scaling apps. It is built on top of Google infrastructure and scales automatically, for even the largest apps, so you don't need to worry about scaling your own servers.

Support for Firebase in Ionic and Angular has been growing recently. Ionic developers can use Firebase to build rich features into their mobile apps. In our website you can find many other Ionic Firebase tutorials and Ionic Firebase free starters.

Firebase offers one of the most powerful and popular Database as a Service (DBaaS) solutions available today. It provides a scalable NoSQL cloud database to store and sync data for client and server side development.

It's important to mention that firebase has a freemium model and is not open source like Ionic, however, you can use it for free if you don't pass the limits of their free tier. So if you plan to build a big application with lots of users check their pricing page before starting. Depending on your needs, you may be fine with the Free tier.

Firebase Cloud Firestore, the database we will use in this tutorial, is a scalable and flexible database for mobile, web, and server development. It keeps your data synchronized across client apps through real time listeners and also offers offline support for mobile and web so you can build responsive apps that work regardless of the Internet connectivity.

At IonicThemes we are big fans of learning by example, that's why all our Ionic tutorials include a complete and free app that you can reuse in your own projects.

For this angular firebase tutorial we created an Ionic CRUD app. The app has a list of contacts that can be queried, edited, and deleted. Also, new contacts can be added. To build this demo app we also used Angular so you will find examples of Angular Forms usage.

For more information on how to use and validate forms in Ionic framework apps make sure to check out the Ionic Angular Forms tutorial.

Well, the first step is to create an Ionic Angular app. You can either download the demo app we built for this tutorial by clicking the "GET THE CODE" button from above or you can create your own Ionic app from scratch.

If you're giving your first steps with Ionic Framework, I suggest you read Ionic Framework introduction and key components and How to set up your development environment to build Ionic apps.

Now that you have your Ionic project up and running, let's see how to integrate it with Firebase.

To connect our app with firebase, we will use AngularFire. AngularFire is the official Angular library for Firebase. Basically, it's a library that provides an easy way for Angular developers to use the framework-agnostic Firebase JS SDK.

To install the AngularFire library run the following command from your console: ng add @angular/fire

This command will install @angular/fire and firebase libraries. It will also offer you to select a Firebase project to link to your app.

install angularfire

If you select a project, the configuration needed for Firebase hosting (another tool from firebase) will be added to your Ionic project.

If you haven't created the Firebase project yet, don't worry, you can configure this later.

In order to use the tools provided by firebase, we need to create a Firebase project from the Firebase console.

To create your project, log in to your firebase account and follow the steps to create a new project. Then, enter to your new project dashboard:

firebase dashboard

Click on "Add Firebase to your web app" to see the credentials of your new Firebase application. We need these credentials to bind our Ionic and firebase projects.

firebase ionic integration

The next step is to add these credentials in our Ionic project. Because we are building an Ionic Angular project, we can use the environment.ts file, located at src/environment/.

A project's src/environment/ folder contains the base configuration files for the project.

firebase ionic credentials

Please note that you need to replace the configuration from above with your own credentials.

Now we need to initialize the AngularFire library. Go to your AppModule and add the provideFirebaseApp and provideFirestore imports.

@NgModule({
  declarations: [AppComponent, NewContactPage],
  imports: [
    BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule,
    ReactiveFormsModule,
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideFirestore(() => getFirestore())
  ],
  providers: [
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

In Ionic 5 Full Starter App you will find a ready-made example of how to use Firebase in a real Ionic Angular app. Using a template like this will save you tons of development and design hours and will give your app a professional look and feel.

This starter includes Firebase Authentication and an advanced Firebase CRUD integration with search filters and nested relations.

ionic firebase starter
ionic firebase starter
ionic firebase starter

Well done! We've finished with the set-up part. Now, let me show you how to get data from a firebase database.

Note: In this tutorial we are using the latest version of AngularFire, that is version 7. It has some breaking changes from version 6. AngularFire 7.0 allows us to take full advantage of the new tree-shakable Firebase JS SDK (v9).

Let's start by looking at the project structure of the app we are going to build.

ionic project structure

We are building a CRUD so we need to support all the following use cases:

  • Create a new contact
  • Read all contacts
  • Update an existing contact
  • Delete a contact

Let's see how to perform each of these operations using a Firebase database.

Inside the services folder we have a DataService that contains all the methods needed to get and save data to our firebase database. Also, we created a Contact data model with the data structure that we need.

List all Contacts

The HomePage has an ionic list component that displays all the contacts from the database. Also, It has an Icon inside the toolbar that triggers the opening of a modal to add a new contact.

ionic list

Firestore database is a non relational database so it arranges its data in collections and documents.

In the DataService we have the getContacts method:

getContacts(): Observable<Contact[]> {
  const contactsCollection = collection(this.firestore, 'contacts');
// this method returns a stream of documents mapped to their payload and id
  return collectionData(contactsCollection, {idField: 'id'})
  .pipe(
    map(contacts => contacts as Contact[])
  );
}

Basically it gets all the documents from the Contacts collection and returns an Observable with a list of our Contact data model.

From the HomePage constructor we call this getContacts() method to load all the contacts into the list.

<ion-list>
 <ion-item *ngFor="let contact of contacts | async" [routerLink]="'/contact-details/' + contact.id">
   <ion-label>{{ contact.firstName }} {{ contact.lastName }}</ion-label>
 </ion-item>
</ion-list>

Create a Contact

For the Create use case, we are going to use an Ionic Modal. To open the modal from the home page we use the following code:

async openNewContactModal() {
  const modal = await this.modalController.create({
    component: NewContactPage,
    swipeToClose: true,
    presentingElement: this.routerOutlet.nativeEl
  });

  return await modal.present();
}
ionic modal

This modal contains a form to add a new contact. For this tutorial we are using Ionic and Angular so, for the forms we use the Angular ReactiveFormsModule. Handling user input with forms is the cornerstone of many common applications that's why we created a specific tutorial about Ionic Angular Forms.

Our Contact model has the following fields:

export class Contact {
  id: string;
  firstName: string;
  lastName: string;
  phone: string;
  email: string;
  category: ContactCategory;
}

export enum ContactCategory {
  FRIEND = "Friend",
  FAMILY = "Family"
}

Because Firestore is a non relational database, you don't need to create the data structure inside the database like you should definitely do in a relational database.

So, the first time you insert a document into a collection, the collection will be created if it doesn't exist.

Once the contact data is submitted, we call the createContact(contact: Contact) method from our DataService.

createContact(contact: Contact): Promise<void> {
  const document = doc(collection(this.firestore, 'contacts'));
  return setDoc(document, contact);
 }

This code adds a new document to the contacts collection in our Firestore database.

We chose to use an auto generated document ID, but if you prefer you can set your own document ID.

firestore database

In this tutorial we will not cover the Add Photo functionality. You can learn about this in How to upload an image to Firebase from an Ionic app.

Update a Contact

To update a contact, first we have to retrieve it. To do this we created the getContactById(id: string) method that gets a snapshot of a specific document from the contacts collection.

getContactById(id: string): Observable<Contact> {
  const document = doc(this.firestore, `contacts/${id }`);
  return docSnapshots(document)
  .pipe(
    map(doc => {
      const id = doc.id;
      const data = doc.data();
      return { id, ...data  } as Contact;
     })
  );
 }

The docSnapshots() returns a DocumentSnapshot, which contains a lot of information about "what happened" with each change. Because we only want to get the data and the id of the document, we use the map operator.have to retrieve it. To do this we created the getContactById(id: string) method that gets a snapshot of a specific document from the contacts collection.

ionic crud app

Once we fetch the data of the contact we want to edit, we load the UpdateContactPage. We will also use an angular form here with all the data preloaded.

ionic crud app
this.updateContactForm = new FormGroup({
  'firstName': new FormControl(this.contact.firstName, Validators.required),
  'lastName': new FormControl(this.contact.lastName, Validators.required),
  'email': new FormControl(this.contact.email),
  'phone': new FormControl(this.contact.phone, Validators.required),
  'category': new FormControl(this.contact.category, Validators.required)
});

We want to enable the “Done” button only if any of the form values are changed. To do this we have to keep an eye on the form valueChanges event. In the following code we subscribe to the valueChanges event and mark the form as edited.

this.updateContactForm.valueChanges.subscribe(values => {
  this.formIsEdited = true;
})

Once the form is submitted, we call the updateContact method that saves the Contact in our Firebase Database.

updateContact(contact: Contact): Promise<void> {
  const document = doc(this.firestore, 'contacts', contact?.id);
  const { id, ...data } = contact; // we don't want to save the id inside the document
  return setDoc(document, data);
}

Delete a Contact

And lastly, to delete a contact we use the deleteDoc method from firebase and then navigate to the home page (the one with the Contacts list).

deleteContact(id: string): Promise<void> {
  const document = doc(this.firestore, 'contacts', id);
  return deleteDoc(document);
}

To improve the UX of this use case you should add an alert with a confirm action.

In this Ionic Firebase tutorial we focused on the database integration so we didn't get into details about navigation best practices in Ionic apps. However, I would like to add some words on this topic.

Navigation is one of the most important parts of an app. Solid navigation patterns help us achieve great user experience while a great router implementation will ease the development process and at the same time make our apps discoverable and linkable.

Navigation is indeed one of the most important elements of user experience, in fact, a bad navigation can frustrate users to an extent that they end up uninstalling the app and even posting a negative review about your app on the app store. So, you don't want to ignore it.

In the Ionic app we built for this tutorial we loaded all the data inside the components. From my point of view, this is not a good practice from a UX perspective.

The approach I suggest for Angular apps is to use Angular Resolvers. The resolvers are helpful to resolve data during navigation. The angular router waits for the data to be resolved before the route is finally activated.

This technique enables us to avoid displaying a blank or incomplete page while waiting for the data to load, which translates in a better user experience and perceived performance.

Also, route resolvers allow you to handle errors before navigating to the component. There's no point in navigating to the contact details page with a specific contact ID if that ID doesn't exist on the database. It'd be better to send the user back to the Contacts Listing page and show him a proper error message.

There are a lot of best practices and gotchas when we talk about navigation and routing in ionic angular apps so make sure to invest time on this topic too.

In this Ionic firebase database tutorial, we explained how to create and set up an Ionic application that gets and saves data to a Firebase database.

We built an Ionic Firebase app with all the operations needed to Create, Read, Update, and Delete Contacts data to a database.

Firebase can be a great option to build apps fast. In addition to databases, it provides other tools such as Authentication, Hosting, Push Notifications, Analytics, and Storage, among others.

You can download the entire code of this project by clicking the "GET THE CODE" button from the beginning of this page.

If you wish to keep learning about Firebase and Ionic, we have top notch guides about Ionic Firebase authentication and also about Building a complete Ionic Firebase App step by step.

I hope this tutorial was helpful for you. If you have any questions or feedback don't hesitate to leave a comment on the section below.

Don't forget to check our premium Ionic templates. I'm confident you would find them extremely useful to kick-start your next Ionic app.