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 existing files.
  • It makes the file immediately downloadable through 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 adds a permanent download token to the underlying GC storage. It also returns the bearer URL (tokenized URL that embeds this very access token, and is not subject to security rules).

We can store it in a database, return it to the client, or discard it and let the client SDK generates the URL on its own with getDownloadURL() (since it is now downloadable).

const url = await getDownloadURL(fileRef)

We can invalidate the access token from the Firebase console. It makes the file non-downloadable. The bearer URL becomes invalid.

advanced: read and write the token

The token, if present, is in the File's metadata field. We should avoid setting this field manually when using save(). We use getDownloadURL instead (see full example below).

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 existing files.
  • It makes the file immediately downloadable through 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 adds a permanent download token to the underlying GC storage. It also returns the bearer URL (tokenized URL that embeds this very access token, and is not subject to security rules).

We can store it in a database, return it to the client, or discard it and let the client SDK generates the URL on its own with getDownloadURL() (since it is now downloadable).

const url = await getDownloadURL(fileRef)

We can invalidate the access token from the Firebase console. It makes the file non-downloadable. The bearer URL becomes invalid.

advanced: read and write the token

The token, if present, is in the File's metadata field. We should avoid setting this field manually when using save(). We use getDownloadURL instead (see full example below).

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)
//  ...