Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Firebase Cloud Functions image thumbnail generator using Sharp for 4x faster resizing
const functions = require('firebase-functions');
const gcs = require('@google-cloud/storage')();
const sharp = require('sharp')
const _ = require('lodash');
const path = require('path');
const os = require('os');
exports.generateThumbnail ='uploads/{imageId}').onChange(event => {
const object =; // The Storage object.
const fileBucket = object.bucket; // The Storage bucket that contains the file.
const filePath =; // File path in the bucket.
const contentType = object.contentType; // File content type.
const resourceState = object.resourceState; // The resourceState is 'exists' or 'not_exists' (for file/folder deletions).
const metageneration = object.metageneration; // Number of times metadata has been generated. New objects have a value of 1.
const SIZES = [64, 256, 512]; // Resize target width in pixels
if (!contentType.startsWith('image/') || resourceState == 'not_exists') {
console.log('This is not an image.');
if (_.includes(filePath, '_thumb')) {
console.log('already processed image');
const fileName = filePath.split('/').pop();
const bucket = gcs.bucket(fileBucket);
const tempFilePath = path.join(os.tmpdir(), fileName);
return bucket.file(filePath).download({
destination: tempFilePath
}).then(() => {
_.each(SIZES, (size) => {
let newFileName = `${fileName}_${size}_thumb.png`
let newFileTemp = path.join(os.tmpdir(), newFileName);
let newFilePath = `thumbs/${newFileName}`
.resize(size, null)
.toFile(newFileTemp, (err, info) => {
bucket.upload(newFileTemp, {
destination: newFilePath
"name": "functions",
"description": "Cloud Functions for Firebase",
"dependencies": {
"@google-cloud/storage": "^0.4.0",
"firebase-admin": "^4.1.2",
"firebase-functions": "^0.5",
"lodash": "^4.17.4",
"request-promise": "^2.0.0",
"sharp": "^0.18.1"
"private": true
Copy link

kuddl commented Oct 4, 2017

thank you very much... this is a great example! very useful

Copy link

ix-xerri commented Nov 1, 2017

I'm trying to use your example but to generate thumbnails inside Firebase Storage. I am not restricting to the uploads/ folder as I want it in different folder ({user}/avatar/{imageId}) in my case. I am getting an error in the Firebase functions log ApiError: Forbidden at new util.ApiError (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:107:10)
Do I have to add a certificate as mentioned here?

Copy link

amitbravo commented Mar 14, 2018

cloud function with sharp , it takes around 8-10 seconds to generate a single thumbnail from a single image file . tell me this is normal .

Copy link

itwasmattgregg commented Jun 28, 2018

onChange() is now deprecated. you should change it to onFinalize()

Copy link

psanders commented Oct 10, 2018

cloud function with sharp , it takes around 8-10 seconds to generate a single thumbnail from a single image file . tell me this is normal .

I'm having the same issue.

Copy link

ProdigyMaster commented Jan 5, 2019

TypeError: gcs.bucket is not a function
at (/user_code/index.js:33:22)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:135:20)
at /var/tmp/worker/worker.js:769:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)

Copy link

wobsoriano commented Apr 21, 2020

UPDATE 2020:

This still works, you have to change some code:

1 . Change

const gcs = require('@google-cloud/storage')();


const { Storage }  = require('@google-cloud/storage');
const gcs = new Storage()
  1. onChange() is now deprecated. Change it to onFinalize().

  2. If you are using "fs-extra": "^9.0.0", downgrade it to version 8.1.0. Why? v9.0.0 requires node version >= 10 it seems, whereas cloud functions are still stable only for node v8 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment