264

I am considering using Firebase as MBaaS, however I couldn't find any reliable solution to the following problem:

I would like to set up two separate Firebase environments, one for development and one for production, but I don't want to do a manual copy of features (eg. remote configuration setup, notification rules, etc.) between the development and production environment.

Is there any tool or method I can rely on? Setting up remote configuration or notification rules from scratch can be a daunting task and too risky.

Any suggestions? Is there a better approach than having two separate environments?

Before you post another answer to the question which explains how to set up separate Firebase accounts: it is not the question, read it again. The question is: how to TRANSFER changes between separate dev and prod accounts or any better solution than manually copy between them.

racs
  • 3,974
  • 2
  • 23
  • 26
  • 4
    https://firebase.googleblog.com/2016/07/deploy-to-multiple-environments-with.html – Timmerz Feb 20 '17 at 20:38
  • @Timmerz See first answer: only relevant to hosting and database, but not to other features. – racs Feb 22 '17 at 06:30
  • I had a similar problem.I solved it in the following way: Check this: https://stackoverflow.com/questions/51646512/how-to-find-the-users-which-are-part-of-a-firebase-app I solved this in following way : 1.create a debug configuration Please follow the link medium.com/@Miqubel/… https://medium.com/@Miqubel/multiple-build-types-in-firebase-on-android-6f6715f6dd83 2.Then create a new database Please follow the link: https://firebase.google.com/docs/database/usage/sharding#when_to_shard_your_data 3.In your code based on your product flavor connect to the corresponding database based on the product – Kunal Khaire Aug 02 '18 at 11:32
  • @KunalKhaire That is not the problem, you can connect to separate Firebase environments easily by adding separate configurations into the build flavors. The issue is moving the changes on the Firebase level between these environments. Say you develop a new remote config in dev, how can that be applied on prod env without too much fuss. – racs Aug 03 '18 at 22:52
  • 1
    @LOG_TAG What's your reasoning for creating an entirely new tag? Does this address any new technologies not already covered by [firebase]? – Michael Dodd Mar 06 '19 at 08:51
  • @MichaelDodd #askfirebase is the more popular hashtag that comes under google firebase developer QA! to get more visibility for the problem we are facing I created that, any feedback? https://twitter.com/search?q=%23askfirebase – LOG_TAG Mar 06 '19 at 10:22
  • @LOG_TAG Tags tend to reflect the technology used or problem outlined in the question. Importing twitter hashtags seem superfluous at best, from the [tags help page](https://stackoverflow.com/help/tagging): *"you should only create new tags when you feel you can make a strong case that your question covers a new topic that nobody else has asked about before on this site."* - In my opinion [askfirebase] doesn't meet that criteria, though we can take it to meta if you feel it should be a tag. – Michael Dodd Mar 06 '19 at 10:39
  • It may help you if you want to follow stevecowling solution: https://stackoverflow.com/questions/48649120/how-to-create-multi-environment-dbs-with-firestore/55027566#55027566 – Quentin C Mar 06 '19 at 16:16

12 Answers12

80

If you are using firebase-tools there is a command firebase use which lets you set up which project you are using for firebase deploy

firebase use --add will bring up a list of your projects, select one and it will ask you for an alias. From there you can firebase use alias and firebase deploy will push to that project.

In my personal use, I have my-app and my-app-dev as projects in the Firebase console.

Lunchbox
  • 2,136
  • 7
  • 29
  • 40
  • 2
    As far as I understood Firebase tools are useful for deploying hosted files and database, but it does not do anything with database, analytics or remote config. Or am I missing something? – racs Oct 22 '16 at 04:58
  • @racs it looks like this is recent, but I'm about to start trying to use the cli for data seeding / data maintenance on my dev instance: https://firebase.googleblog.com/2015/11/the-firebase-cli-now-with-database_82.html – Chris Nov 09 '16 at 22:58
  • @chris thanks, it is a start at least. But it looks like a rather arcane thing to do. Good luck! – racs Nov 12 '16 at 07:20
  • @racs as far as seeding data and development flow goes, it's worked out really well. I can reliably mutate my dev database based on versioned npm run commands and versioned seed data. You were looking for a way to copy meta data as well but I haven't seen that unfortunately. – Chris Nov 12 '16 at 15:03
  • @Chris thanks for letting us know about it. This is still an open question as far as I can tell. – racs Nov 12 '16 at 21:59
  • @Lunchbox, How are you limiting access to your "my-app-dev" instance? For example, are you specifying which domains or users can access your page? – Luke Becker Nov 28 '16 at 18:32
  • @LukeBecker I am not limiting anything atm. My current Firebase stuff is just a toy app. I've been trying to get familiar with the infrastructure. – Lunchbox Nov 28 '16 at 18:56
  • but this also means paying twice ..? – ProblemsOfSumit Sep 21 '17 at 11:18
  • Any ideas about binding the default project to a custom domain and a dev project to a different subdomain? That way you can test before going into production within the same firebase project – Andres Biarge Apr 29 '18 at 16:55
67

As everyone has pointed out - you need more than one project/database.

But to answer your question regarding the need to be able to copy settings/data etc from development to production. I had the exact same need. A few months in development and testing, I didn't want to manually copy the data.

My result was to backup the data to a storage bucket, and then restore it from there into the other database. It's a pretty crude way to do it - and I did a whole database backup/restore - but you might be able to look in that direction for a more controlled way. I haven't used it - it's very new - but this might be a solution: NPM Module firestore-export-import

Edit: Firestore backup/export/import info here Cloud Firestore Exporting and Importing Data

If you're using Firebase RTDB, and not Firestore - this documentation might help: Firebase Automated Backups

You will need to set the permissions correctly to allow your production database access to the same storage bucket as your development. Good luck.

stevecowling
  • 946
  • 9
  • 7
  • 3
    Thanks, this is the best answer so far. – racs Feb 17 '19 at 03:02
  • 8
    For any project that has a few thousand users, you will end up moving *some* data from a production database to a staging or development server. It's a shame this isn't built into Firebase, but it's something that would need to be done for any type of project. –  Dec 08 '19 at 23:35
  • I imported the database using the "Moving data between projects" guide. But it created the Firestore database in Datastore mode. I need to use it in Native mode. – Debiprasad Jun 02 '20 at 14:28
  • 2
    in addition to "As everyone has pointed out" https://firebase.google.com/docs/projects/dev-workflows/overview-environments and the next Site Generell best practices – Alexander Sidikov Pfeif Nov 28 '22 at 12:00
  • 1
    Firebase is great but it has a long way to go, it seems a beta product, like a lot of features missing, thanks for this answer upvoted althought I'm not satisfied with the FB. – guilherme victor ramalho natal Jan 04 '23 at 20:18
28

I'm not currently using Firebase, but considering it like yourself. Looks like the way to go is to create a completely separate project on the console. There was a blogpost up recommending this on the old Firebase site, looks to be removed now though. https://web.archive.org/web/20160310115701/https://www.firebase.com/blog/2015-10-29-managing-development-environments.html

Also this discussion recommending same: https://groups.google.com/forum/#!msg/firebase-talk/L7ajIJoHPcA/7dsNUTDlyRYJ

Patrick Jackson
  • 18,766
  • 22
  • 81
  • 141
  • 3
    Thanks for the answer. Having two separate projects is most likely the only option. However, copying data between them is complicated at best. I wonder if Firebase Tools could copy rules, audience setup, etc. It seems to me that it deals with database-related operations only: https://github.com/firebase/firebase-tools – racs May 28 '16 at 04:31
  • So far my conclusion is the same as yours: two separate project is the solution, even if it is inconvenient: there are no easy methods to move data between the projects. – racs Jun 14 '16 at 22:59
  • 2
    Not sure if you've seen this, but you can run your dev against a firebase-server: https://firebase.googleblog.com/2015/04/end-to-end-testing-with-firebase-server_16.html – krico Jul 21 '16 at 21:05
  • @krico Not quite sure how could this project be useful. What I want to achieve is developing Firebase-related features on one instance and then deploy them to the production instance. Do you have any hints? – racs Jul 28 '16 at 13:30
  • @racs, in that case all I've found is what was suggested, create a second firebase application and use it for dev. – krico Aug 02 '16 at 02:29
  • 2
    That is exactly what I have done, but the question is: how can you copy any setup between the two environment? Eg. remote configs, audience setup, etc? Adding these manually to the production environment is rather error prone. – racs Aug 03 '16 at 08:25
  • 2
    A problem I've run into is authentication with multiple firebase instances with the same package and signature. The console will not allow you to add the same package sha1 to more than one project, so this may not be possible. The docs say there is a work around by whitelisting clientid, but I have not had success with that. The other work around is seperate package names (more accurately 'applicationIds)' but then there are other complications – Patrick Jackson Aug 27 '16 at 20:08
  • I've found solution for the above problem! Is possible to auth to multiple firebases. It is detailed here https://groups.google.com/forum/m/#!topic/firebase-talk/GnmClQZ4nCs – Patrick Jackson Aug 28 '16 at 13:27
  • 3
    Also read this: https://firebase.googleblog.com/2016/08/organizing-your-firebase-enabled-android-app-builds.html – racs Sep 27 '16 at 02:35
22

The way I did it:

  1. I had 2 projects on firebase- one for DEV other for PROD
  2. Locally my app also had 2 branches - one named DEV, the other named PROD
  3. In my DEV branch I always have JSON file of DEV firebase project & likewise for PROD

This way I am not required to maintain my JSONs.

TT.
  • 15,774
  • 6
  • 47
  • 88
Kunal Khaire
  • 307
  • 2
  • 7
  • 2
    I do understand,but there is no generic solution to the asked question as per the latest firebase version. You have to play with the current options & derive a best practise. May be my answer was not pointing this,but i just want to help the asker with my perspective. – Kunal Khaire Aug 09 '18 at 11:35
12

You will need to manage different build types

Follow this

  1. First, create a new project at Firebase console, name id as YOURAPPNAME-DEV

  2. Click "Add android app" button and create a new app. Name it com.yourapp.debug, for example. New google-services.json file will be downloaded automatically

  3. Under your project src directory create new directory with name "debug" and copy new google-services.json file here

  4. In your module level build.gradle add this

    debug {
            applicationIdSuffix ".debug"
        }
    

Now when you build a debug build google-services.json from "debug" folder will be used and when you will build in release mode google-services.json from module root directory will be considered.

ColdLogic
  • 7,206
  • 1
  • 28
  • 46
Chetan Gaikwad
  • 1,268
  • 1
  • 13
  • 26
  • 1
    In case anyone needs the official documentation, The Google Services Gradle Plugin knows to look for the google-services.json under the subdirectory of `src` for the buildType as explained here https://developers.google.com/android/guides/google-services-plugin#adding_the_json_file – Michael Osofsky Aug 07 '19 at 03:35
12

I'm updating this answer based on information I just found.

Step 1

In firebase.google.com, create your multiple environments (i.e.; dev, staging, prod)


mysite-dev

mysite-staging

mysite-prod


Step 2

a. Move to the directly you want to be your default (i.e.; dev)

b. Run firebase deploy

c. Once deployed, run firebase use --add

d. An option will come up to select from the different projects you currently have.

Scroll to the project you want to add: mysite-staging, and select it.

e. You'll then be asked for an alias for that project. Enter staging.

Run items a-e again for prod and dev, so that each environment will have an alias


Know which environment you're in

Run firebase use default (mysite-dev)

* dev (mysite-dev)

staging (mysite-staging)

prod (mysite-dev)

(one of the environments will have an asterisk to the left of it. That's the one you're currently in. It will also be highlighted in blue)


Switch between environments

Run firebase use staging or firebase use prod to move between them.

Once you're in the environment you want, run firebase deploy and your project will deploy there.

Here's a couple helpful links...

CLI Reference

Deploying to multiple environments

Hope this helps.

Millhorn
  • 2,953
  • 7
  • 39
  • 77
  • 2
    When you say multiple environments, you mean multiple projects? – walidvb Jul 26 '20 at 00:15
  • I mean multiple environments. Read the post **[here](https://firebase.googleblog.com/2016/07/deploy-to-multiple-environments-with.html)** for clarification. That's how it's titled. It has to do with the same project but on dev/qa and production. – Millhorn Jul 26 '20 at 20:21
  • 11
    Thanks, I just watched the video in its entirety. This said, I understand that he uses different _projects_ for the different environments, not a dedicated environment _within_ the same project – walidvb Jul 27 '20 at 08:10
10

We chose to fire up instances of the new Firebase emulator on a local dev server for Test and UAT, leaving GCP out of the picture altogether. It's designed exactly for this use-case.

https://firebase.google.com/docs/emulator-suite

belwood
  • 3,320
  • 11
  • 38
  • 45
  • How do you do integration tests with your apps? – racs Feb 01 '21 at 23:55
  • Can you elaborate? I'm not sure I understand what you mean by "how". We generally follow the instructions in the firevase emulator docs. – belwood Feb 02 '21 at 06:53
  • I wasn't clear enough: do you do all your integration tests by connecting to an emulated Firebase host? Is that sufficiently mimicing the real services? – racs Feb 03 '21 at 07:07
  • Yes. Outside of CORS, security and other non-functional issues, we see no differences. – belwood Feb 03 '21 at 16:25
  • Thanks, good to hear. I am going to give it a try when I have the opportunity. Sounds better than setting up a separate full environment. – racs Feb 06 '21 at 04:12
  • 2
    Be careful about assuming that the emulators are fully-sufficient testing environments. For example, emulated Firestore does not throw any errors for queries that require a composite index to be set up, whereas a real Firestore (cloud-based) instance does. – Jason Frank May 03 '22 at 15:38
  • 1
    See: https://firebase.google.com/docs/emulator-suite/connect_firestore#how_the_emulator_differs_from_production – Jason Frank May 03 '22 at 15:53
8

This blogpost describes a very simple approach with a debug and release build type.

In a nutshell:

  • Create a new App on Firebase for each build type using different application id suffix.
  • Configure your Android project with the latest JSON file.
  • Using applicationIdSuffix, change the Application Id to match the different Apps on Firebase depending on the build type.

=> see the blogpost for a detailed description.

If you want to use different build flavors, read this extensive blogpost from the official firebase blog. It contains a lot of valuable information.

Hope that helps!

Lukas Lechner
  • 7,881
  • 7
  • 40
  • 53
  • Thanks for your reply. I was able to set up different apps, yet I am still looking for a method to copy various setup from FB dev app to FB prod app as I asked for in the question. (Eg. remote config or audience settings.) – racs Dec 05 '16 at 06:47
  • 3
    Please note this creates two apps inside the same project therefore you will separate some services such as analytics but the database will be shared so is not a real separation of environments as explained here https://firebase.googleblog.com/2016/08/organizing-your-firebase-enabled-android-app-builds.html – AntPachon Jun 20 '17 at 18:44
6

To solve this for my situation I created three Firebase projects, each with the same Android project (i.e. same applicationId without using the applicationIdSuffix suggested by others). This resulted in three google-services.json files which I stored in my Continuous Integration (CI) server as custom environment variables. For each stage of the build (dev/staging/prod), I used the corresponding google-services.json file.

For the Firebase project associated with dev, in its Android project, I added the debug SHA certificate fingerprint. But for staging and prod I just have CI sign the APK.

Here is a stripped-down .gitlab-ci.yml that worked for this setup:

# This is a Gitlab Continuous Integration (CI) Pipeline definition
# Environment variables:
#   - variables prefixed CI_ are Gitlab predefined environment variables (https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)
#   - variables prefixed GNDR_CI are Gitlab custom environment variables (https://docs.gitlab.com/ee/ci/variables/#creating-a-custom-environment-variable)
#
# We have three Firebase projects (dev, staging, prod) where the same package name is used across all of them but the
# debug signing certificate is only provided for the dev one (later if there are other developers, they can have their
# own Firebase project that's equivalent to the dev one).  The staging and prod Firebase projects use real certificate
# signing so we don't need to enter a Debug signing certificate for them.  We don't check the google-services.json into
# the repository.  Instead it's provided at build time either on the developer's machine or by the Gitlab CI server
# which injects it via custom environment variables.  That way the google-services.json can reside in the default
# location, the projects's app directory.  The .gitlab-ci.yml is configured to copy the dev, staging, and prod equivalents
# of the google-servies.json file into that default location.
#
# References:
# https://firebase.googleblog.com/2016/08/organizing-your-firebase-enabled-android-app-builds.html
# https://stackoverflow.com/questions/57129588/how-to-setup-firebase-for-multi-stage-release

stages:
  - stg_build_dev
  - stg_build_staging
  - stg_build_prod

jb_build_dev:
  stage: stg_build_dev
  image: jangrewe/gitlab-ci-android
  cache:
    key: ${CI_PROJECT_ID}-android
    paths:
      - .gradle/
  script:
    - cp ${GNDR_CI_GOOGLE_SERVICES_JSON_DEV_FILE} app/google-services.json
    - ./gradlew :app:assembleDebug
  artifacts:
    paths:
      - app/build/outputs/apk/

jb_build_staging:
  stage: stg_build_staging
  image: jangrewe/gitlab-ci-android
  cache:
    key: ${CI_PROJECT_ID}-android
    paths:
      - .gradle/
  dependencies: []
  script:
    - cp ${GNDR_CI_GOOGLE_SERVICES_JSON_STAGING_FILE} app/google-services.json
    - ./gradlew :app:assembleDebug
  artifacts:
    paths:
      - app/build/outputs/apk/

jb_build_prod:
  stage: stg_build_prod
  image: jangrewe/gitlab-ci-android
  cache:
    key: ${CI_PROJECT_ID}-android
    paths:
      - .gradle/
  dependencies: []
  script:
    - cp ${GNDR_CI_GOOGLE_SERVICES_JSON_PROD_FILE} app/google-services.json

    # GNDR_CI_KEYSTORE_FILE_BASE64_ENCODED created on Mac via:
    # base64 --input ~/Desktop/gendr.keystore --output ~/Desktop/keystore_base64_encoded.txt
    # Then the contents of keystore_base64_encoded.txt were copied and pasted as a Gitlab custom environment variable
    # For more info see http://android.jlelse.eu/android-gitlab-ci-cd-sign-deploy-3ad66a8f24bf
    - cat ${GNDR_CI_KEYSTORE_FILE_BASE64_ENCODED} | base64 --decode > gendr.keystore

    - ./gradlew :app:assembleRelease
      -Pandroid.injected.signing.store.file=$(pwd)/gendr.keystore
      -Pandroid.injected.signing.store.password=${GNDR_CI_KEYSTORE_PASSWORD}
      -Pandroid.injected.signing.key.alias=${GNDR_CI_KEY_ALIAS}
      -Pandroid.injected.signing.key.password=${GNDR_CI_KEY_PASSWORD}
  artifacts:
    paths:
      - app/build/outputs/apk/

I'm happy with this solution because it doesn't rely on build.gradle tricks which I believe are too opaque and thus hard to maintain. For example, when I tried the approaches using applicationIdSuffix and different buildTypes I found that I couldn't get instrumented tests to run or even compile when I tried to switch build types using testBuildType. Android seemed to give special properties to the debug buildType which I couldn't inspect to understand.

Virtuously, CI scrips though are quite transparent and easy to maintain, in my experience. Indeed, the approach I've described worked: When I ran each of the APKs generated by CI on an emulator, the Firebase console's "Run your app to verify installation" step went from

Checking if the app has communicated with our servers. You may need to uninstall and reinstall your app.

to:

Congratulations, you've successfully added Firebase to your app!

for all three apps as I started them one by one in an emulator.

Michael Osofsky
  • 11,429
  • 16
  • 68
  • 113
  • Thank you for all this detailed description, Michael. I managed the same outcome by simply adding separate flavors and copy the appropiate google-services.json under the folders for each flavor. However, this was not my question, please read it again. – racs Aug 11 '19 at 04:59
  • I agree @racs but unfortunately when I wrote https://stackoverflow.com/questions/37450439/separate-dev-and-prod-firebase-environment, it was marked as a duplicate of your question by https://stackoverflow.com/users/807126/doug-stevenson – Michael Osofsky Aug 11 '19 at 16:17
  • 2
    Doug... What have you done! :D I don't mind your answer here, I am sure it is helpful to some people who is seeking a solution for the separate environment. – racs Aug 13 '19 at 06:43
  • 1
    yeah, we have been looking a solution for our mobile application that needs separate environments with firebase service. This definitely a good starting point for us. We will try it out. – L.T. Sep 26 '19 at 13:31
1

Firebase has a page on this which goes through how to set it up for dev and prod

https://firebase.google.com/docs/functions/config-env

Set environment configuration for your project To store environment data, you can use the firebase functions:config:set command in the Firebase CLI. Each key can be namespaced using periods to group related configuration together. Keep in mind that only lowercase characters are accepted in keys; uppercase characters are not allowed.

For instance, to store the Client ID and API key for "Some Service", you might run:

firebase functions:config:set someservice.key="THE API KEY" someservice.id="THE CLIENT ID"

Retrieve current environment configuration To inspect what's currently stored in environment config for your project, you can use firebase functions:config:get. It will output JSON something like this:

{
  "someservice": {
    "key":"THE API KEY",
    "id":"THE CLIENT ID"
  }
}
CorayThan
  • 17,174
  • 28
  • 113
  • 161
Derek Dawson
  • 502
  • 5
  • 14
  • 1
    Resolves to a 404. Next time include the contents as well! – CorayThan Dec 11 '18 at 17:48
  • this doesn't say anything about separating dev and prod, it just talks about how to set up env variables. Is there a way to easily switch between configs for dev and prod? – bze12 Dec 04 '21 at 00:01
1

Create the Tow project with Dev and production Environment on the firebase Download the json file from thre

and setup the SDK as per : https://firebase.google.com/docs/android/setup Or for Crashlytics: https://firebase.google.com/docs/crashlytics/get-started?platform=android

First, place the respective google_services.json for each buildType in the following locations:

app/src/debug/google_services.json
app/src/test/google_services.json
app/google_services.json

Note: Root app/google_services.json This file should be there according to the build variants copy the json code in the root json file

Now, let’s whip up some gradle tasks in your: app’s build.gradle to automate moving the appropriate google_services.json to app/google_services.json

copy this in the app/Gradle file

task switchToDebug(type: Copy) {
description = 'Switches to DEBUG google-services.json'
from "src/debug"
include "google-services.json"
into "."
}

task switchToRelease(type: Copy) {
description = 'Switches to RELEASE google-services.json'
from "src/release"
include "google-services.json"
into "."
}

Great — but having to manually run these tasks before you build your app is cumbersome. We would want the appropriate copy task above run sometime before: assembleDebug or :assembleRelease is run. Let’s see what happens when :assembleRelease is run: copy this one in the /gradlew file

Zaks-MBP:my_awesome_application zak$ ./gradlew assembleRelease
Parallel execution is an incubating feature.
.... (other tasks)
:app:processReleaseGoogleServices
....
:app:assembleRelease

Notice the :app:processReleaseGoogleServices task. This task is responsible for processing the root google_services.json file. We want the correct google_services.json to be processed, so we must run our copy task immediately beforehand. Add this to your build.gradle. Note the afterEvaluate enclosing.

copy this in the app/Gradle file

afterEvaluate {
processDebugGoogleServices.dependsOn switchToDebug
processReleaseGoogleServices.dependsOn switchToRelease
}

Now, anytime :app:processReleaseGoogleServices is called, our newly defined :app:switchToRelease will be called beforehand. Same logic for the debug buildType. You can run :app:assembleRelease and the release version google_services.json will be automatically copied to your app module’s root folder.

Shaikh Mohib
  • 278
  • 3
  • 11
  • 2
    You have put a lot of energy into this answer, but 1. this has nothing to do with the question (please read it again), 2. you don't have to copy the `google-services.json` file to the root folder, if you keep it in the flavour folder that is perfectly fine. Instead `assembleRelease` you can just invoke an `assembleTestRelease` task. – racs Dec 03 '19 at 01:07
0

The way we are doing it is by creating different json key files for different environments. We have used service account feature as recommended by google and have one development file and another for production

enter image description here

vsingh
  • 6,365
  • 3
  • 53
  • 57