20

I'm using firebase for auth and db, and AWS lambda for cloud functions.

To add firebase to my JS project, I initializeApp with the firebase config as parameter, as documented here : https://firebase.google.com/docs/web/setup.

As documented here : https://firebase.google.com/docs/admin/setup, I also need to initializeApp in my lambda function.

Something as follows here :

const admin = require('firebase-admin');
const serviceAccount = require('../path/to/service-account.json');

const firebaseAdmin = admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "dB_URL"
});

The credentials come from the firebase-admin library, so I cannot add this to my web firebase config. So, I need to initialize twice.

However, if I proceed like this, the server will throw an error :

The default Firebase app already exists. This means you called initializeApp() more than once without providing an app name as the second argument. In most cases you only need to call initializeApp() once.But if you do want to initialize multiple apps, pass a second argument to initializeApp() to give each app a unique name.

Am I missing something here ? What's the best practice ? I'm confused.

Someone faced the same issue before it seems : Use Firebase SDK with Netlify Lambda Functions

What worked for this user was to use the REST API as documented here : https://firebase.google.com/docs/projects/api/workflow_set-up-and-manage-project

The documentation says it's in beta though.

Thanks for your kind help

6 Answers 6

57

It seems that lambda may load the script file that calls admin.initializeApp({...}) multiple times. To prevent the Admin SDK from initializing multiple times, you can for example detect if that already happened:

if (!admin.apps.length) {
    const firebaseAdmin = admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        databaseURL: "dB_URL"
    });
}

As cnexans commented, if you're on the modular API the equivalent would be:

if (!getApps().length) {
  ...
Sign up to request clarification or add additional context in comments.

5 Comments

Awesome. That worked. Thanks for the tip. Now I have another related issue : I can declare a document reference. However a get() request to get the data containted in that document returns the following error message : "Error getting document: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type number". It's the error logged from the catch, as in documented here : firebase.google.com/docs/firestore/query-data/get-data. Can't tell whether it is Firebase related. Sorry if it's not.
It looks like you're passing in a number, while keys/ids are always strings. If they're numeric values, convert it to a string first with something like 42.toString() or ''+42. Please note that in general it's best to open a new question for... uhm... new questions like this. ;-)
I'm sorry, I don't get it. Where am I passing a number ? I'm doing a basic get request, as in the official documentation. Which keys/ids are you referring to ? (Noted. I wasn't sure as it's somewhat related)
If my comment doesn't explain it well enough, open a new question with the minimal standalone code that anyone can run to reproduce the problem.
This will do the work export const app = getApps().length === 0 ? initializeApp(firebaseAdminConfig, "server") : getApp("server");
9

Have similar problem. Based on answer from @Frank van Puffelen ( Thanks to him ), Now a days, Using ES6 ( Firebase admin V >= 9 )

import { initializeApp, applicationDefault, getApps } from "firebase-admin/app";

...

        if ( !getApps().length ) {
            initializeApp({
                credential: applicationDefault(),
                databaseURL: 'https://XXXXXXX.firebaseio.com'
            });
        }
...

2 Comments

What does this answer add to the one already written by Frank?
@DanDascalescu , it is a matter of code syntax. While Frank's answer is written in CommonJS, mine is written in ES6, besides the syntax, it has a different approach to writing JS modules. It could be a little confusing for a few developers during the transition of Firebase SDK team from Common JS to ES6.
6

An alternative in the simplest case might be something like this:

import { initializeApp, getApp } from "firebase-admin/app";

function appSingleton () {
  try {
    return getApp()
  } catch (err) {
    return initializeApp()
  }
}

Comments

0

if you used initializeApp() more than once, you could add the app name after you add the option object parameter. This will be more useful for you.

const firebaseAdmin = admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "dB_URL"
},"give-your-app-name");

Comments

0

I tried this and it works. declare all those needed such as initialize, at the top.

 const serviceAccount = require("./serviceAccountKey.json");  
 const readyToUser = admin.initializeApp({
 credential: admin.credential.cert(serviceAccount),   
 databaseURL: "https://hello.firebaseio.com",   
  });

then in the function part just

exports.deleteuser = onDocumentDeleted("user/{uid}", (event) => {
 const snap = event.data;
 const data = snap.data();
 return readyToUser.auth().deleteUser(event.params.uid);  
 });

Comments

-1

so my mistake is i write initializeApp in seperate function every time it calls that function produce this avoid are you initialize app ones it ok dont initialize again and again

1 Comment

If you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. - From Review

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.