Pascal Luther
Oct 31, 2018 · 6 min read

This article will help you integrate Firebase Firestore into a Nuxt.js project while keeping the server-side rendering capabilities that come with the amazing Universal SSR mode of Nuxt.js.

And all of this without the need for any additional libraries other than Google’s own Firebase SDK.

❗️️️️️️❗️️️️️️ Update: If you like it even simpler: I wrote a small Nuxt module that makes integrating Firebase into your Nuxt 2.0 project even easier! Check it out:
https://github.com/lupas/nuxt-fire

❗️️ This article is based on Nuxt.js v2.x and might not be valid for older versions. For an article covering the same for Nuxt.js v1.x, check out the following article:
https://medium.com/@pascalluther/nuxt-js-v1-firestore-and-ssr-73e3140574fc

1) Install Nuxt.js

skip to section 2 if you already have a Nuxt.js project running

Follow the instructions on the link below to create a basic nuxt app:

https://github.com/nuxt/create-nuxt-app

npx create-nuxt-app <my-project>

❗️️ Make sure to replace “<project-name>” with your project-name!

You can choose which options you like yourself, but make sure to have rendering mode “universal” applied so it is a SSR project.

? Project name nuxt2-firestore
? Project description My ultimate Nuxt.js project
? Use a custom server framework none
? Use a custom UI framework none
? Choose rendering mode Universal ❗️️❗️️❗️️
? Use axios module no
? Use eslint no
? Use prettier no
? Author name Pascal
? Choose a package manager npm

After following the installation instruction you should be able to run your project and see the following:

2) Install the Firebase SDK

skip to section 3 if you already have the Firebase SDK installed

Now let’s install the Firebase SDK. Do this with the following command:

npm install firebase --save

This is all the dependencies you will need. In your packages.json file you should see the below:

"dependencies": {
"cross-env": "^5.2.0",
"firebase": "^5.5.6",
"nuxt": "^2.0.0"
},

The starter template comes with Nuxt v.2.0.0. Change that to ^2.2.0 or higher and then run npm install to update to a more recent version, just for the sake of not using a rather old version.

This article was written with the following two versions:

"dependencies": {
"cross-env": "^5.2.0",
"firebase": "^5.5.6",
"nuxt": "^2.2.0"
},

3) Initiate the Firebase SDK

Now let’s finally write some code. 🎉

We want to make sure that the Firebase SDK is initiated on the server, so the server can get data from Firestore and render it before it gets sent to the client.

In your /plugins folder, create a file called firebase.js and add the following code:

import firebase from 'firebase/app'
import 'firebase/firestore'
if (!firebase.apps.length) { const config = {
apiKey: '<replace this>',
authDomain: '<replace this>',
databaseURL: '<replace this>',
projectId: '<replace this>',
storageBucket: '<replace this>',
messagingSenderId: '<replace this>'
}
firebase.initializeApp(config)
firebase.firestore().settings({timestampsInSnapshots: true})
}
const fireDb = firebase.firestore()export {fireDb}

❗️️ Make sure to replace “<replace this>” with your Firebase credentials. I will refrain from explaining how to setup a Firebase project and getting the credentials, since this is well documented in the Firebase docs here.

Now we add the plugin to our nuxt.config.js like so:

plugins: [
'~/plugins/firebase.js'
],

4) Write to Firestore

Now we can already write something to Firestore! 🤩

Delete all content in your pages/index.vue file and replace it with the following:

<template>
<section class="container">
<div>
<h2>
Write to Firestore.
</h2>
<div>
<button @click="writeToFirestore" :disabled="writeSuccessful">
<span v-if="!writeSuccessful">Write now</span>
<span v-else>Successful!</span>
</button>
</div>
</div>
</section>
</template>
<script>
import {fireDb} from '~/plugins/firebase.js'
export default {
data() {
return {
writeSuccessful: false
}
},
methods: {
async writeToFirestore() {
const ref = fireDb.collection("test").doc("test")
const document = {
text: "This is a test message."
}
try {
await ref.set(document)
} catch (e) {
// TODO: error handling
console.error(e)
}
this.writeSuccessful = true
}
}
}
</script>
<style>
.container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
</style>

Your app should now look like this:

When clicking on “Write now”, the button should change to “Successful!” and there should be a collection “test” with a document named “test” in your Firestore database:

A document named “test” should now exist within a collection called “test”.

❗️️ If this did not work, make sure your project and Firestore is set up properly. You might have to setup an instance of Firestore first. Also, make sure that your security rules are defined as public (but change that later on!).

5) Read from Firestore

Now let’s read what we wrote to the Firestore!

Add a second <div> below the “Write to Firestore”-Div like so:

<div>
<h2>
Read from Firestore.
</h2>
<div>
<button @click="readFromFirestore" :disabled="readSuccessful">
<span v-if="!readSuccessful">Read now</span>
<span v-else>Successful!</span>
</button>
<p>{{text}}</p>
</div>
</div>

Add the attributes readSuccessful and text to your data, so it looks like this:

data() {
return {
writeSuccessful: false,
readSuccessful: false,
text: ""
}
},

And finally add a method to read the data from Firestore like below:

async readFromFirestore() {
const ref = fireDb.collection("test").doc("test")
let snap
try {
snap = await ref.get()
} catch (e) {
// TODO: error handling
console.error(e)
}
this.text = snap.data().text
this.readSuccessful = true
}

Now try it out!

After clicking both buttons, your app should look like this:

Below the “Read” button, the text written to Firestore should appear.

That’s it. You can now already read and write to Firebase Firestore with Nuxt.js!

But wait… that is a client side request to Firestore. 😱 That has nothing to do with SSR.

Well, read on.

6) Server-side Rendering (SSR)

If you want your page to render the data from Firestore already on server-side, simply do it as you are used to with Nuxt.js — by adding an asyncData function like so (more Infos here):

async asyncData({app, params, error}) {
const ref = fireDb.collection("test").doc("test")
let snap
try {
snap = await ref.get()
} catch (e) {
// TODO: error handling
console.error(e)
}
return {
text: snap.data().text
}
},

Now if you reload your page, the call to Firebase will be done server side.

That’s already it! We successfully implemented Nuxt.js with Firebase Firestore! 🎉🎉

Additional Content

Entire index.vue:

<template>
<section class="container">
<div>
<h2>
Write to Firestore.
</h2>
<div>
<button @click="writeToFirestore" :disabled="writeSuccessful">
<span v-if="!writeSuccessful">Write now</span>
<span v-else>Successful!</span>
</button>
</div>
</div>
<div>
<h2>
Read from Firestore.
</h2>
<div>
<button @click="readFromFirestore" :disabled="readSuccessful">
<span v-if="!readSuccessful">Read now</span>
<span v-else>Successful!</span>
</button>
<p>{{text}}</p>
</div>
</div>
</section>
</template>
<script>
import {fireDb} from '~/plugins/firebase.js'
export default {
data() {
return {
writeSuccessful: false,
readSuccessful: false,
text: ""
}
},
async asyncData({app, params, error}) {
const ref = fireDb.collection("test").doc("test")
let snap
try {
snap = await ref.get()
} catch (e) {
// TODO: error handling
console.error(e)
}
return {
text: snap.data().text
}
},
methods: {
async writeToFirestore() {
const ref = fireDb.collection("test").doc("test")
const document = {
text: "This is a test message."
}
try {
await ref.set(document)
} catch (e) {
// TODO: error handling
console.error(e)
}
this.writeSuccessful = true
},
async readFromFirestore() {
const ref = fireDb.collection("test").doc("test")
let snap
try {
snap = await ref.get()
} catch (e) {
// TODO: error handling
console.error(e)
}
this.text = snap.data().text
this.readSuccessful = true
}
}
}
</script>
<style>
.container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
</style>

Links:

Thanks & Credits to:

Pascal Luther

Written by

Business Analyst for zuehlke.com by day, recreational hobby-coder by night. Currently a big fan of Vue & Nuxt.js and of going serverless with Google Firebase.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade