Search code examples
javascriptfirebasenext.jsfirebase-hostingfirebase-admin

Firebase-admin won't initialize on a next js app deployed on Firebase


I'm trying to deploy a Next JS app to Firebase hosting using the web framework option firebase-tools has. The only issue I've encoutered is that firebase-admin seems to never initialize when I try to use it to fetch data, or do anything related with it. This is how I'm initializing it, it works locally:

firebase/firebaseAdminInit.ts

import admin from 'firebase-admin';

export function GetFirebaseAdminApp() {
    if(admin.apps.length === 0){
        const app = admin.initializeApp({
            credential:admin.credential.cert({
                clientEmail: process.env.NEXT_FIREBASE_CLIENT_EMAIL as string,
                projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID as string,
                privateKey: process.env.NEXT_FIREBASE_PRIVATE_KEY as string
            }),
            databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL as string,
            storageBucket: process.env.NEXT_PUBLIC_STORAGE_BUCKET as string
        });
        return app;
    }
    return admin.app();
}

How I use it:

lib/repository/products.ts

import { getFirelord, getFirestore, getDocs, query, orderBy, limit, offset, getCountFromServer, addDoc, updateDoc, getDoc, deleteDoc } from "firelord";
import { ProductsMetaType } from "./dtoModels";
import { Product, ProductRequest, productToDomain, productType_toDto } from "../domain/Products";
import { GetFirebaseAdminApp } from "../../firebase/firebaseAdminInit";
import { PagedQuery, PagedResult } from "../domain/PagedQueries";
import formidable from "formidable";
import { DeleteImage, UploadImage } from "./objectStorage";

const app = getFirestore(GetFirebaseAdminApp()); //This should return the firebase-admin app
const productFl = getFirelord<ProductsMetaType>(app, 'Products');

export async function GetAllProducts() {
    const docs =
        await getDocs(productFl.collection()).then(qSnapshot =>
            qSnapshot.docs.map(docSnapshot => docSnapshot.data())
        ).then(dtoArr => dtoArr.map(productToDomain))
    return docs;
}

When I try to log the app in the firebaseAdminInit.ts file I see that there's something, not a undefined or null value, but when it gets used somewhere else it fails saying it's not initialized:

FirebaseAppError: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services.


Solution

  • Seems like if I try to get the app by checking if there's an app already initialized, or if I define a function checking in what env I'm working on (dev or prod) I'll always get an error. firebase-admin NEEDS to be initialized like this to run on firebase functions:

    const app = admin.initializeApp({
        credential:admin.credential.cert({
            clientEmail: process.env.NEXT_FIREBASE_CLIENT_EMAIL as string,
            projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID as string,
            privateKey: process.env.NEXT_FIREBASE_PRIVATE_KEY as string
        }),
        databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL as string,
        storageBucket: process.env.NEXT_PUBLIC_STORAGE_BUCKET as string
    })
    

    This will give me errors when testing locally (dev) but it will work on prod, which is annoying having to rewrite this block of code each time I want to deploy or test locally.

    I used dependency injection to pass the app to all the functions that need firebase-admin and I'm exporting them from the file where firebase-admin is being initialized, but I haven't tried just getting the app by writing admin.app(), that might work too.

    I'm also having a lot of errors now with firebase functions parsing the body of a request each time and issues with authorization and the name of cookies, so I would recommend others to wait for the web framework support for next js to be better if you want to deploy on firebase as me.