Back to blog

Basic tips for your first Firebase project

Posted

A couple of weeks ago I decided that I wanted to build and launch a new project in a few days. To achieve that, I'd need to simplify as much as possible my tasks so I thought it was the perfect moment to learn Firebase and use it in a project for the first time. The project is still under development but so far I've learnt a few lessons I'd like to share.

Why should you use Firebase?

The main reason I had to use Firebase was curiosity. I've been wanting to try it for a while now and with the launch of AWS Amplify (which is pretty similar) my curiosity kicked in again. But other factors can make you decide to choose Firebase. For example:

My 8 tips when working with Firebase

I hope you find the reasons above enough compelling to try Firebase but before that, let me tell you a few tips that I think would make your project development event better:

Use the Firebase CLI and VSCode extensions

You can install the CLI running npm i firebase-tools -g and then authenticate running firebase login with your Google credentials (did I mentioned Firebase is owned by Google?). In addition, the two VSCode extensions I installed are Firebase Explorer and Firestore Rules.

Create two Firebase projects

In order to keep your develop and production environments completely isolated, I'd create two different projects in Firebase (for example myAwesomeApp and myAwesomeApp-dev). Each project will have its own database, hosting and, more important, its own quotas so all the tests you'll do will not affect your live environment. You can create the project using the Firebase CLI or, better, create them manually in the Firebase Console website.

Vuejs + Firebase project scaffold

As mentioned earlier, the project I'm creating is a web built with Vuejs so to start I ran vue create my-project-name. Then inside the project folder, run firebase init and selected the features you want, like Hosting or Firestore . Next, choose the development project you created in the previous step and finally, the CLI will ask you for the files where it'll define the Firestore rules and indexes. Once your project is scaffolded, you can do your first deployment!

Setup deployment scripts for each environment/project

Once your Firebase project is initialized, you can deploy it running firebase deploy. This is ok to deploy to the Firebase project you chose when you initialized the project, but as we want to target different projects (remember we have develop and production), I suggest to create different scripts in your package.json file. Here are the ones I have:

  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "deploy-rules-dev": "firebase deploy --project myAwesomeApp-dev --only firestore:rules",
    "deploy-rules-production": "firebase deploy --project myAwesomeApp --only firestore:rules",
    "deploy-functions-dev": "firebase deploy --project myAwesomeApp-dev --only functions",
    "deploy-functions-production": "firebase deploy --project myAwesomeApp --only functions",
    "deploy-dev": "vue-cli-service build --mode development && firebase deploy --project myAwesomeApp-dev",
    "deploy-production": "vue-cli-service build --mode production && firebase deploy --project myAwesomeApp"
  },

As you can see the firebase CLI has different flags we can use:

Use environment variables

This is very obvious but you should use environment variables to load you Firebase project keys or other variables that would be different in each environment. For example, initialise your app like this:

// ⛔️ DONT
const firebaseApp = firebase.initializeApp({
  apiKey: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  authDomain: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  databaseURL: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  projectId: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  storageBucket: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  messagingSenderId: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  appId: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  measurementId: 'xxxXXXXXxxXXXXxxXXXXxxxx',
})
// ✅ DO 
const firebaseApp = firebase.initializeApp({
  apiKey: process.env.VUE_APP_APIKEY,
  authDomain: process.env.VUE_APP_AUTHDOMAIN,
  databaseURL: process.env.VUE_APP_DATABASEURL,
  projectId: process.env.VUE_APP_PROJECTID,
  storageBucket: process.env.VUE_APP_STORAGEBUCKET,
  messagingSenderId: process.env.VUE_APP_MESSAGINGSENDERID,
  appId: process.env.VUE_APP_APPID,
  measurementId: process.env.VUE_APP_,
})

In my case, I'm using Vuejs so I just need to create two files named .env.development and .env.production locally and whenever I run npm run build, it will automatically replace the environment variables with the values from the correspondent file. You can read more about Vuejs environment variables here.

Think twice your data model and don't be afraid to duplicate

Before you start coding, think about how your app is going to look like, which data you are going to need in each page and which pages are going to be more used. This is pretty important because it will affect the way you'll store your data in Firestore (the noSQL database used in Firebase) or the Real Time Database.

As one of the limitations of the free tier is the number of documents your app reads and writes, consider doing it just when you need it.

One of the things that have made me save a ton of document reads is duplication of some fields. This is something not very common in relational databases (I'd say it's even forbidden 😅) where we use foreign keys and join queries but it's pretty normal in noSQL databases. You can read more about data modelling and view some videos in this section of the docs.

Create functions for your Firestore rules

Once you start defining Firestore rules, there are two functions that you'll use all the time:

For that, you can create the following functions in your firestore.rules file:

//**** Functions   ****//
function isLoggedIn(){
  return request.auth != null;
}
function isOwner(){
  return request.auth.id ==resource.data.uid;
}

You can find more info about security rules here.

Paginate and limit your queries

This comes back to the limitations of the free tier. Just remember to add a limit(x) to your collection queries whenever you are going to access your data. You don't want to return 150 documents when on your page you can only display 20. Pagination is super simple to build thanks to the startAfter() method. Find below an example of how I'm doing pagination in my Vuejs app:

// part of store/index.js file

// global variable to store last paginated element
let paginationLast = null

// Vuex store action
getUpcomingTalks({ commit }, payload) {
  return new Promise((resolve, reject) => {
    talksCollection
      .orderBy('date', 'asc')
      .limit(payload.limit || 12)
      .startAfter(paginationLast)
      .get()
      .then((res) => {
        if (res.docs.length > 0) {
          // save last item for pagination
          paginationLast = res.docs[res.docs.length - 1]

          commit('GET_UPCOMING_TALKS', res.docs)
          return resolve()
        } else {
          reject({ hasMore: false })
        }
      })
      .catch((err) => {
        console.log('err in action :>> ', err)
        return reject()
      })
  })
},

Just remember:

Conclusion

I still have a ton of things to learn about Firebase but I'd say these are the more important things I've learnt so far. Hope you find them useful.

Included in categories

coding javascript tooling firebase
Related articles

If you enjoyed this article consider sharing it on social media or buying me a coffee ✌️

Buy me a coffeeBuy me a coffee

Oh! and don't forget to follow me on Twitter where I share tons of dev tips 🤙