Skip to content

feat(storage): support content encoding uploads#2322

Open
yashwanth8634 wants to merge 1 commit into
supabase:developfrom
yashwanth8634:storage-content-encoding
Open

feat(storage): support content encoding uploads#2322
yashwanth8634 wants to merge 1 commit into
supabase:developfrom
yashwanth8634:storage-content-encoding

Conversation

@yashwanth8634

Copy link
Copy Markdown

This pull request adds support for specifying contentEncoding values, such as gzip, when uploading files via the storage client. The change ensures that content encoding is passed through correctly during both standard uploads and signed URL uploads.

What changed?

  • Added a new optional contentEncoding field to the FileOptions interface.
  • Updated StorageFileApi to pass contentEncoding through upload requests:
    • For raw file bodies, it sets the content-encoding header.
    • For multipart uploads, such as Blob, File, or FormData, it includes contentEncoding as a form field.
  • Added tests covering contentEncoding behavior for both upload() and uploadToSignedUrl().

Why it changed

The storage client already supports related upload metadata such as contentType and cacheControl, but did not expose a first-class way to set Content-Encoding.

This is useful for pre-compressed assets, such as gzip-encoded files, where callers need the stored object to preserve the correct encoding metadata.

Closes #1883

How to test

Run the focused storage test:

cd packages/core/storage-js
../../../node_modules/.bin/jest test/storageFileApi.test.ts --runInBand --testNamePattern contentEncoding --watchman=false

Copilot AI review requested due to automatic review settings May 4, 2026 14:08
@yashwanth8634 yashwanth8634 requested review from a team as code owners May 4, 2026 14:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class contentEncoding support to the storage client’s upload flows so callers can preserve encoding metadata (e.g. gzip) when uploading pre-compressed assets, including via signed upload URLs.

Changes:

  • Added optional contentEncoding to FileOptions.
  • Passed contentEncoding through uploads: as a content-encoding header for raw bodies, and as a contentEncoding multipart form field for Blob/FormData.
  • Added Jest tests validating contentEncoding behavior for both upload() and uploadToSignedUrl().

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
packages/core/storage-js/src/lib/types.ts Adds contentEncoding to the public upload options type.
packages/core/storage-js/src/packages/StorageFileApi.ts Forwards contentEncoding through both standard and signed uploads (header vs multipart field depending on body type).
packages/core/storage-js/test/storageFileApi.test.ts Adds test coverage ensuring contentEncoding is propagated for both raw and multipart upload bodies.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

*/
contentType?: string
/**
* The `Content-Encoding` header value. Useful when uploading already-compressed file bodies, for example `gzip`.
Comment on lines 97 to +102
if (typeof Blob !== 'undefined' && fileBody instanceof Blob) {
body = new FormData()
body.append('cacheControl', options.cacheControl as string)
if (options.contentEncoding) {
body.append('contentEncoding', options.contentEncoding)
}
const [, , body] = mockPost.mock.calls[0]
expect((body as FormData).get('contentEncoding')).toBe('gzip')
})

@mandarini

Copy link
Copy Markdown
Contributor

Thanks for the contribution @yashwanth8634, and for the clean, well-tested implementation. Before I can merge this on the client side, we need the storage server to actually honor Content-Encoding on uploads. I traced the request through the current supabase/storage master and confirmed:

  • The standard upload route that @supabase/storage-js calls (fileUploadFromRequestUploader.uploadbackend.uploadObject) never extracts content-encoding from headers or the contentEncoding form field. The fields it reads are content-type, cache-control, x-robots-tag, x-metadata, plus cacheControl / metadata / contentType form fields.
  • Even the S3-compat PutObject route extracts ContentEncoding from headers but then drops it inside s3Protocol.putObject (src/storage/protocols/s3/s3-handler.ts) before calling Uploader.upload. The backend uploadObject adapter signature has no slot for it.

So as-is, this PR would advertise an option that has no effect, callers would assume their object has Content-Encoding: gzip stored when in fact it's silently dropped, which is worse than the current state.

Would you be up for opening a feature request on https://github.com/supabase/storage proposing that the standard upload route (and ideally the S3-compat route too) persist Content-Encoding into the object metadata and return it on read? Once the server side is in, this client PR becomes a small, safe follow-up and we can revisit it. Happy to revisit this one as soon as that lands.

A couple of smaller notes for when we do revisit:

  • The Copilot review flagged that the TSDoc on contentEncoding says "the Content-Encoding header value", but for Blob/FormData uploads it's actually sent as a multipart form field, worth tweaking the wording to describe both transports.
  • Also flagged a missing test for the FormData passthrough de-dup branch (!body.has('contentEncoding')), mirroring the existing cacheControl de-dup test.

Also FYI, this PR targets develop. I changed the default branch, and it should be master. So can you please recreate the PR to target master?

You can do this very easily.

  1. Check out master on your local
  2. Fetch and pull latest changes
  3. Go on a new branch
  4. git cherry-pick 0df0466c9a71f8dffb981838a141135c51f52a2c to add your commit

@mandarini mandarini added needs server code This feature/fix needs changes on the server side, before the client side changes can take effect. do-not-merge Do not merge this PR. labels May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge Do not merge this PR. needs server code This feature/fix needs changes on the server side, before the client side changes can take effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for setting the Content-Encoding header when uploading files to Storage

3 participants