Firebase SDK for Cloud Functions migration Guide: beta to version 1.0 or 2.0

Version 1.0.0 of the Firebase SDK for Cloud Functions introduces some important changes in the API. The primary change, a replacement of event.data format with data and context parameters, affects all asynchronous (non-HTTP) functions. The updated SDK can also be used with firebase-functions-test, a brand new unit testing companion SDK. See Unit Testing Functions for more information.

Version 2.0.0 of the Firebase SDK for Cloud Functions introduces a breaking change for timestamps in Firestore-triggered functions.

To update SDKs to the latest version, run the following in the functions folder:

npm install firebase-functions@latest --save
npm install firebase-admin@latest --save-exact

You should also update Firebase CLI to the latest version:

npm install -g firebase-tools

SDK changes that affect all asynchronous (non-HTTP) functions

SDK changes by trigger type

New and Legacy API References

Changes to functions emulation

SDK changes that affect all background (non-HTTP) functions

Event parameter split into data and context

As of v 1.0 of the Firebase SDK for Cloud Functions, the event parameter for asynchronous functions is obsolete. It has been replaced by two new parameters: data and context.

The data parameter represents the data that triggered the function. The fields of the data parameter are determined by the trigger type, and vary accordingly. For example, for Realtime Database, the data parameter is a DataSnapshot. See changes by trigger type for more information on the data parameter.

The context parameter provides information about the function's execution. Identical across asynchronous functions types, context contains the fields eventId, timestamp, eventType, resource, and params. Additionally, Realtime Database functions provide authentication information for the user that triggered the function. Here's an example of context fields defined in a function triggered by a Realtime Database write:

exports.dbWrite = functions.database.ref('/path/with/{id}').onWrite((data, context) => {
  const authVar = context.auth; // Auth information for the user.
  const authType = context.authType; // Permissions level for the user.
  const pathId = context.params.id; // The ID in the Path.
  const eventId = context.eventId; // A unique event ID.
  const timestamp = context.timestamp; // The timestamp at which the event happened.
  const eventType = context.eventType; // The type of the event that triggered this function.
  const resource = context.resource; // The resource which triggered the event.
  // ...
});

New initialization syntax for firebase-admin

firebase-admin is now initialized without any parameters within the Cloud Functions runtime.

Before (<= v0.9.1)

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

Now (>= v1.0.0)

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

Note that you can no longer pass in functions.config().firebase when initializing. See the following section for details on how to access configuration in v1.0.0.

functions.config().firebase removed

functions.config().firebase has been removed. If you'd like to access the config values from your Firebase project, use process.env.FIREBASE_CONFIG instead:

let firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG);
/* {  databaseURL: 'https://databaseName.firebaseio.com',
       storageBucket: 'projectId.appspot.com',
       projectId: 'projectId' }
*/

SDK changes by trigger type

For many supported function triggers, v 1.0 introduces changes in the naming for data fields and methods. This section lists the changes by trigger type.

Realtime Database

Event data now a DataSnapshot

In earlier releases, event.data was a DeltaSnapshot; now in v 1.0 it is a DataSnapshot.

For onWrite and onUpdate events, the data parameter has before and after fields. Each of these is a DataSnapshot with the same methods available in admin.database.DataSnapshot. For example:

Before (<= v0.9.1)

exports.dbWrite = functions.database.ref('/path').onWrite((event) => {
  const beforeData = event.data.previous.val(); // data before the write
  const afterData = event.data.val(); // data after the write
});

Now (>= v1.0.0)

exports.dbWrite = functions.database.ref('/path').onWrite((change, context) => {
  const beforeData = change.before.val(); // data before the write
  const afterData = change.after.val(); // data after the write
});

For onCreate, the data parameter is a DataSnapshot that represents the data that was just added:

Before (<= v0.9.1)

exports.dbCreate = functions.database.ref('/path').onCreate((event) => {
  const createdData = event.data.val(); // data that was created
});

Now (>= v1.0.0)

exports.dbCreate = functions.database.ref('/path').onCreate((snap, context) => {
  const createdData = snap.val(); // data that was created
});

For onDelete, the data parameter is a DataSnapshot that represents the data that was just deleted:

Before (<= v0.9.1)

exports.dbDelete = functions.database.ref('/path').onDelete((event) => {
  const deletedData = event.data.previous.val(); // data that was deleted
});

Now (>= v1.0.0)

exports.dbDelete = functions.database.ref('/path').onDelete((snap, context) => {
  const deletedData = snap.val(); // data that was deleted
});

New properties for user auth information

EventContext.auth V1.0.0 introduces two new properties for accessing user information, including permissions, for the user that triggered a function.

  • EventContext.auth. Contains information such as uid and the authenticated user's auth token.
  • EventContext.authType. Contains permissions levels, allowing you to detect whether the user is an admin user, for example.

Developers using the undocumented event.auth fields should update any related code to use these new properties.

adminRef replaced by ref

The .adminRef reference is now removed in favor of the .ref reference which is now authorized with administrator privileges. The former way of using .ref—as a reference to the change authorized as the user which triggered the change—is no longer supported.

Before (<= v0.9.1)

exports.dbCreate = functions.database.ref('/path/{uid}').onCreate((event) => {
  const parentRef = event.data.adminRef.parent; // The Database reference to the parent authorized with admin privileges.

  const parentRefAsUser = event.data.ref.parent; // The Database reference to the parent authorized as the user which triggered the change.
});

Now (>= v1.0.0)

exports.dbCreate = functions.database.ref('/path/{uid}').onCreate((snap, context) => {
  const parentRef = snap.ref.parent; // The Database reference to the parent authorized with admin privileges
});

You can still perform user-authorized changes to the Realtime Database using the admin SDK:

const functions = require('firebase-functions');
const admin = require('firebase-admin');

exports.impersonateMakeUpperCase = functions.database.ref('/messages/{pushId}/original')
    .onCreate((snap, context) => {
      const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
      appOptions.databaseAuthVariableOverride = context.auth;
      const app = admin.initializeApp(appOptions, 'app');
      const uppercase = snap.val().toUpperCase();
      const ref = snap.ref.parent.child('uppercase');

      const deleteApp = () => app.delete().catch(() => null);

      return app.database().ref(ref).set(uppercase).then(res => {
        // Deleting the app is necessary for preventing concurrency leaks
        return deleteApp().then(() => res);
      }).catch(err => {
        return deleteApp().then(() => Promise.reject(err));
      });
    });

Cloud Firestore

Much like the Realtime Database changes for v 1.0, onWrite and onUpdate have a data parameter which has before and after fields. Events for onCreate and onDelete both have a data parameter that is a Cloud Firestore DocumentSnapshot.

Before (<= v0.9.1)

exports.dbWrite = functions.firestore.document('/doc/path').onWrite((event) => {
  const beforeData = event.data.previous.data(); // data before the write
  const afterData = event.data.data(); // data after the write
});

Now (>= v1.0.0)

exports.dbWrite = functions.firestore.document('/doc/path').onWrite((change, context) => {
  const beforeData = change.before.data(); // data before the write
  const afterData = change.after.data(); // data after the write
});

Events for onCreate and onDelete both have a data parameter that is a DocumentSnapshot.

Before (<= v0.9.1)

exports.dbDelete = functions.firestore.document('/doc/path').onDelete((event) => {
  const deletedData = event.data.previous.data(); // data that was deleted
});

Now (>= v1.0.0)

exports.dbDelete = functions.firestore.document('/doc/path').onDelete((snap, context) => {
  const deletedData = snap.data(); // data that was deleted
});

Breaking Change in v2.0.0 for Firestore timestamps

As of v2.0.0 of Firebase SDK for Cloud Functions, timestamp values in a Firestore snapshot received inside of a function are Firestore Timestamp objects. This applies to snapshot.createTime, snapshot.updateTime, snapshot.readTime, and any timestamp values in snapshot.data()

Now (>= v2.0.0)

exports.dbCreate = functions.firestore.document('/doc/path').onCreate((snap, context) => {
  //seconds of UTC time since Unix epoch
  console.log(snap.createTime.seconds);

  //fractions of a second at nanosecond resolution, 0 to 999,999,999
  console.log(snap.createTime.nanoseconds);
});

Authentication

In earlier releases, event.data.metadata contained the deprecated fields createdAt and lastSignedInAt. Version 1.0 removes these fields completely and replaces them with creationTime and lastSignInTime fields in the userRecord.metadata parameter.

Before (<= v0.9.1)

// This code won't work with Cloud Functions SDK 1.0 and higher!
exports.authAction = functions.auth.user().onCreate((event) => {
  const userMetadata = event.data.metadata;

  const creationTime = userMetadata.createdAt; // 2016-12-15T19:37:37.059Z
  const lastSignInTime = userMetadata.lastSignedInAt; // 2018-01-03T16:23:12.051Z
}

Now (>= v1.0.0)

exports.authAction = functions.auth.user().onCreate((userRecord, context) => {
  const creationTime = userRecord.metadata.creationTime; // 2016-12-15T19:37:37.059Z
  const lastSignInTime = userRecord.metadata.lastSignInTime; // 2018-01-03T16:23:12.051Z
}

Crashlytics

In v 1.0, the event handler that fires every time a new issue occurs is onNew. The previous handler named onNewDetected has been removed.

Before (<= v0.9.1)

exports.newIssue = functions.crashlytics.issue().onNewDetected((event) => {
  const issue = event.data;

  const issueId = issue.issueId;
  const issueTitle = issue.issueTitle;
  const appName = issue.appInfo.appName;
  const appId = issue.appInfo.appId;
  const appPlatform = issue.appInfo.appPlatform;
  const latestAppVersion = issue.appInfo.latestAppVersion;
  const createTime = issue.createTime;
}

Now (>= v1.0.0)

exports.newIssue = functions.crashlytics.issue().onNew((issue, context) => {
  const issueId = issue.issueId;
  const issueTitle = issue.issueTitle;
  const appName = issue.appInfo.appName;
  const appId = issue.appInfo.appId;
  const appPlatform = issue.appInfo.appPlatform;
  const latestAppVersion = issue.appInfo.latestAppVersion;
  const createTime = issue.createTime;
}

Storage

The onChange event handler has been removed. Instead, v 1.0 supports these events:

  • onArchive Only sent when a bucket has enabled object versioning. This event indicates that the live version of an object has become an archived version, either because it was archived or because it was overwritten by the upload of an object of the same name.
  • onDelete Sent when an object has been permanently deleted. This includes objects that are overwritten or are deleted as part of the bucket's lifecycle configuration. For buckets with object versioning enabled, this is not sent when an object is archived (see onArchive), even if archival occurs via the storage.objects.delete method.
  • onFinalize Sent when a new object (or a new generation of an existing object) is successfully created in the bucket. This includes copying or rewriting an existing object. A failed upload does not trigger this event.
  • onMetadataUpdate Sent when the metadata of an existing object changes.

Before (<= v0.9.1)

exports.processFile = functions.storage.object().onChange((event) => {
  const object = event.data;

  const filePath = object.name; // Path of the File
  const contentType = object.contentType; // Mime type of the file

  // Exit if this is a deletion event.
  if (object.resourceState === 'not_exists') {
    console.log('This file was deleted.');
    return null;
  }

  // Exit if file exists but is not new and is only being triggered
  // because of a metadata change.
  if (resourceState === 'exists' && metageneration > 1) {
    console.log('This is a metadata change event.');
    return null;
  }

  // ...
}

Now (>= v1.0.0)

exports.processFile = functions.storage.object().onFinalize((object, context) => {
  const filePath = object.name; // Path of the File
  const contentType = object.contentType; // Mime type of the file

  // ...
}

exports.fileDeleted = functions.storage.object().onDelete((object, context) => {
  console.log('This file was deleted.');
}

exports.metadataUpdated = functions.storage.object().onMetadataUpdate((object, context) => {
  console.log('This is a metadata change event.');
}

New and Legacy API References

To learn more, see the API reference for firebase-functions v1.0.0. You can also refer to the API reference for v0.9.1 to aid in your migration.

Changes to functions emulation

  • firebase serve now serves both HTTP functions and hosting by default.
  • firebase experimental:functions:shell, which emulates all functions, has been renamed to firebase functions:shell.

Syntax changes for functions shell

The syntax for invoking functions through the functions shell has been updated to reflect the syntax for firebase-functions v1.0.0.

// Inside functions shell

// To emulate database writes done by an administrative user:
myDbFunction(‘data’)

// To emulate database writes done by an authenticated user:
myDbFunction(‘data’, { auth: { uid: ‘abc’ }})

// To emulate database writes done by an unauthenticated user:
myDbFunction(‘data’, { authMode: ‘UNAUTHENTICATED’)

Send feedback about...

Need help? Visit our support page.