Upload data

client SDK

upload a Blob or a File

We prepare some data in a JavaScript Blob or File object, and upload it to the reference.

const result = await uploadBytes(fileRef, file)
  • The upload is a non-conditional upsert which overrides any existing file.
  • It makes the file immediately downloadable with the SDK read functions.
  • On success, we receive an UploadResult, which wraps the bucket file's metadata and the file reference.
result.metadata // FullMetadata
result.ref

(advanced) upload and track the progress

For each tick, we receive a snapshot. We may show the upload progress.

const uploadTask = uploadBytesResumable(ref, file)

uploadTask.on(
    "state_changed",
    /* on snapshot */
    function (snapshot) {
        // snapshot.bytesTransferred
        // snapshot.totalBytes
        // snapshot.state // "paused" | "running"
    },
    function (error) {},
    function () {
        /* on completion */
        getDownloadURL(uploadTask.snapshot.ref).then(/**/)
    }
)

admin SDK

upload a Node.js Buffer and make it downloadable

We prepare some data in a Node.js Buffer, and upload it to the reference.

await fileRef.save(imageBuffer, {
    resumable: false,
    metadata: {
        contentType: `image/png`,
        cacheControl: "public, max-age=31536000, immutable",
    },
})

Note: it doesn't make the file downloadable for clients: a client getDownloadURL() fails. This is because the underlying GC storage object is missing a Firebase-specific download token in its metadata.

To make it downloadable for clients, we use the admin SDK's getDownloadURL(). It attaches a download token to the underlying GC storage if needed. It also returns a bearer URL (that embeds this very access token and is not subject to security rules). We can store the bearer URL in a database, send it to the client, or discard it since the client can create the URL by itself with its own getDownloadURL().

const url = await getDownloadURL(fileRef)

We may invalidate an access token at any time, from the Firebase console. If we hardcoded bearer URLs in a database, they become invalid.

advanced: controlling the CG object token field

The token, if any, is at the firebaseStorageDownloadTokens metadata's field.

metadata: {
  firebaseStorageDownloadTokens: token
}

upload image example (admin SDK)

We upload an image and make it readable by clients. We may store the bypass URL.

// 1.0 create a file reference
const fileRef = bucket.file(`generated/${userID}/cat.png`)

// 1.1 create a Buffer object
const imageBuffer = base64ToBuffer(base64Data)

// 1.2 upload the Buffer object
await fileRef.save(imageBuffer, {
    resumable: false,
    metadata: {
        contentType: `image/png`,
        cacheControl: "public, max-age=31536000, immutable",
    },
})
//  1.3 make it readable by client SDKs (generate a token).
const url = await getDownloadURL(fileRef)

//  1.4 store the bypass URL (if applicable)
//  ...
earlymorning logo

© Antoine Weber 2026 - All rights reserved

Upload data

client SDK

upload a Blob or a File

We prepare some data in a JavaScript Blob or File object, and upload it to the reference.

const result = await uploadBytes(fileRef, file)
  • The upload is a non-conditional upsert which overrides any existing file.
  • It makes the file immediately downloadable with the SDK read functions.
  • On success, we receive an UploadResult, which wraps the bucket file's metadata and the file reference.
result.metadata // FullMetadata
result.ref

(advanced) upload and track the progress

For each tick, we receive a snapshot. We may show the upload progress.

const uploadTask = uploadBytesResumable(ref, file)

uploadTask.on(
    "state_changed",
    /* on snapshot */
    function (snapshot) {
        // snapshot.bytesTransferred
        // snapshot.totalBytes
        // snapshot.state // "paused" | "running"
    },
    function (error) {},
    function () {
        /* on completion */
        getDownloadURL(uploadTask.snapshot.ref).then(/**/)
    }
)

admin SDK

upload a Node.js Buffer and make it downloadable

We prepare some data in a Node.js Buffer, and upload it to the reference.

await fileRef.save(imageBuffer, {
    resumable: false,
    metadata: {
        contentType: `image/png`,
        cacheControl: "public, max-age=31536000, immutable",
    },
})

Note: it doesn't make the file downloadable for clients: a client getDownloadURL() fails. This is because the underlying GC storage object is missing a Firebase-specific download token in its metadata.

To make it downloadable for clients, we use the admin SDK's getDownloadURL(). It attaches a download token to the underlying GC storage if needed. It also returns a bearer URL (that embeds this very access token and is not subject to security rules). We can store the bearer URL in a database, send it to the client, or discard it since the client can create the URL by itself with its own getDownloadURL().

const url = await getDownloadURL(fileRef)

We may invalidate an access token at any time, from the Firebase console. If we hardcoded bearer URLs in a database, they become invalid.

advanced: controlling the CG object token field

The token, if any, is at the firebaseStorageDownloadTokens metadata's field.

metadata: {
  firebaseStorageDownloadTokens: token
}

upload image example (admin SDK)

We upload an image and make it readable by clients. We may store the bypass URL.

// 1.0 create a file reference
const fileRef = bucket.file(`generated/${userID}/cat.png`)

// 1.1 create a Buffer object
const imageBuffer = base64ToBuffer(base64Data)

// 1.2 upload the Buffer object
await fileRef.save(imageBuffer, {
    resumable: false,
    metadata: {
        contentType: `image/png`,
        cacheControl: "public, max-age=31536000, immutable",
    },
})
//  1.3 make it readable by client SDKs (generate a token).
const url = await getDownloadURL(fileRef)

//  1.4 store the bypass URL (if applicable)
//  ...