Firebase Admin refuses to initialize on a Next.js application that has been deployed on Firebase

Currently, I am facing an issue while attempting to deploy a Next JS app to Firebase hosting using the web framework option provided by firebase-tools. The problem arises when trying to initialize firebase-admin as it seems to never properly initialize when fetching data or performing any related tasks. Here is how I am initializing it, which works fine 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;
}

Upon logging the app in the firebaseAdminInit.ts file, I can see that there is some value present, not null or undefined. However, when used elsewhere, it fails with an error stating that it's not initialized:

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

Answer №1

When attempting to incorporate firebase-admin into Next.js API Routes, I encountered a similar issue. Your workaround proved instrumental in identifying the problem. It seems that directly calling admin.app() or getApp() triggers errors in firebase functions. Instead, utilizing getApps()[0] resolves the issue, although the exact reason remains unclear.

The following code enabled me to successfully import adminAuth and adminFirestore from API Routes:

lib/firebase-admin.ts

import { AppOptions, cert, getApps, initializeApp, ServiceAccount } from "firebase-admin/app";
import { getAuth } from "firebase-admin/auth";
import { getFirestore } from "firebase-admin/firestore";

const credentials: ServiceAccount = {
  projectId: process.env.FIREBASE_ADMIN_SDK_FIREBASE_PROJECT_ID,
  privateKey: process.env.FIREBASE_ADMIN_SDK_PRIVATE_KEY?.replace(/\\n/g, "\n"),
  clientEmail: process.env.FIREBASE_ADMIN_SDK_CLIENT_EMAIL,
};

const options: AppOptions = {
  credential: cert(credentials),
};

export const initializeFirebaseAdmin = () => {
  const firebaseAdminApps = getApps();
  if (firebaseAdminApps.length > 0) {
    return firebaseAdminApps[0];
  }

  return initializeApp(options);
}

const firebaseAdmin = initializeFirebaseAdmin();

export const adminAuth = getAuth(firebaseAdmin);
export const adminFirestore = getFirestore(firebaseAdmin);

Answer №2

It seems that attempting to retrieve the app by checking if it has already been initialized or defining a function to determine the environment (development or production) always leads to an error. In order for firebase-admin to run on Firebase functions, it must be initialized in the following manner:

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 setup results in errors when testing locally (in development), but functions correctly in production. It can be frustrating to have to repeatedly adjust this code block for deployment or local testing.

I've utilized dependency injection to pass the app to functions requiring firebase-admin, exporting them from the file where initialization occurs. I haven't yet tried simply retrieving the app using admin.app(), which may also work.

Currently, I'm encountering numerous issues with firebase functions related to parsing request bodies and problems with authorization and cookie names. As such, I would advise waiting for better web framework support for Next.js before deploying on Firebase like myself.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The A-frame advances in the direction of the camera's view

I need help creating a component in A-frame that can move the player or camera based on the direction it is facing. The movement should be restricted to the x/y plane and not affect the y axis. Currently, my DOM setup looks like this: <a-entity> ...

Utilizing Moment.js in tandem with Vuexfire

As I develop my Vue.js application, I have integrated Vuexfire in a store.js file. The purpose of my application is to allow users to submit posts along with timestamps to Firestore. In order to achieve this functionality, I am configuring my Vuexfire acti ...

Javascript textfield button function malfunctioning

Here is the code I have created: HTML: <form method="post" id="myemailform" name="myemailform" action="form-to-email.php"> <div id="form_container"> <label class="descriptio ...

Unexpected error encountered in the return value from the filter function in AngularJS

My goal is to filter a specific Firebase path and check if a certain child exists within that path. I am interested in retrieving only the values that have a child called "responses". The code works fine when the child exists, but throws an error when it ...

Populating a HTML document with data retrieved from an AJAX request

I have a button that, when clicked, should display the values of a specific user. The code snippet for this functionality is as follows: HTML Button: <button onclick="return getUserDetails(<? echo $user['id']; ?>)" class="btn btn-xs bt ...

Challenge of integrating React Router with Express GET requests

I am struggling to understand how react router and express routes work together. This is what I currently have set up: app.get('*', function(req, res) { res.sendFile(path.resolve(__dirname) + '/server/static/index.html'); }); // ...

Ensuring jQuery filter() works seamlessly with Internet Explorer versions 6, 7, and 8

On my webpage, I have implemented an ajax call using the jQuery library to handle a specific task. After making the ajax call, I need to parse the response message that is returned. However, I encountered an issue with Internet Explorer versions 6, 7, and ...

Obtain the text content in cases where the DOM is missing both the title and value fields

I am trying to extract the value from a text-box using selenium, but the text-box is marked as readonly and aria-live is set to off. Here is the DOM structure: <input autocomplete="off" class="abc" type="text" role="t ...

Leveraging Angular for REST API Calls with Ajax

app.controller('AjaxController', function ($scope,$http){ $http.get('mc/rest/candidate/pddninc/list',{ params: { callback:'JSON_CALLBACK' } }). success(function (data, status, headers, config){ if(ang ...

When the mouse is clicked, rotate the object along its axis using OBJ Loader in THREE.js

I am looking to add a feature where my object rotates on its axis when the mouse is dragged. The challenge I am facing is that I can only access my skull object within the function, which limits where I can place a rotation increment inside render(). Coul ...

Display a JavaScript dialogue box containing a PHP variable

Is there a way to display the correct JavaScript box when using a While loop in PHP? Here is the code snippet: while($result= mysql_fetch_array($data)){ <tr class="<?php echo $style;?>"> <td><?php echo $result['commis ...

Avoid altering the state directly; utilize setState() to update it instead. Remember to follow react/no-direct-mutation

Here's the code snippet I'm working with: constructor(props) { super(props) this.state = { loginButton: '', benchmarkList: '' } if (props.username == null) { this.state.loginButton = &l ...

Saving Arrays through an Input Form in JavaScript

I am working with an HTML form that looks like the following: <div class="form-group"> <label for="first_name">1st Name</label> <input type="text" id="first_name" placeholder="First Name" class="form-control"/> </div> ...

Despite the presence of a producer and topic, sending Kafka messages is proving to be a challenge

Currently, I am using TypeScript and the KafkaJS library on my local machine with a single Kafka broker. After successfully connecting a producer, confirming the creation of my topic, and creating messages like so: const changeMessage = { key: id, ...

Issue with scrolling feature in div

I am currently facing an issue with scrolling on my website. Visit this site to see the problem. When scrolling down, it causes the "hidden" part of the site to slide up. I want to achieve a similar sliding effect, but it needs to be smooth. I have attempt ...

Import HTML document into a Bootstrap Popup

Currently, I am working on creating a modal that loads content dynamically. Below is the JavaScript code I have been using for this task: function track(id,title) { $('#listenTrack').modal('show'); $('#listenTrack').f ...

Concealing the print option while utilizing PDFObject in conjunction with PDF.js

When displaying a file using pdf.js, I encountered issues with the print button and other functionalities. I was able to hide the buttons using CSS for Chrome, but not for Internet Explorer, where I had to resort to using JavaScript. While the JavaScript ...

Transferring information between Express and React through the Contentful API

I have embarked on a journey to explore Contentful's headless CMS, but I am encountering a challenge with their API client. My goal is to combine Express with React for server-side rendering, and I am utilizing this repository as my starting point. S ...

Tips for enabling Angular JS draggable elements on tablet devices with touch functionality

I've been experimenting with an Angular JS draggable directive. The code I'm using closely resembles the one in this Plunker example. While everything runs smoothly on Windows when using a mouse, I've encountered issues with touch-enabled d ...

Why does running "npx create-next-app@12 my-app" result in a Next.js project with version 13 of "next" being used?

Upon using the command npx create-next-app@12 my-app to create a Next.js project, I anticipated that version 12 of "next" would be installed. However, the resulting project is actually utilizing the latest version, which is version 13. To address this dis ...