Skip to content

feat(storage): add version parameter for download#2153

Open
Fruup wants to merge 5 commits intosupabase:masterfrom
Fruup:feat/file-download-versioning
Open

feat(storage): add version parameter for download#2153
Fruup wants to merge 5 commits intosupabase:masterfrom
Fruup:feat/file-download-versioning

Conversation

@Fruup
Copy link
Copy Markdown

@Fruup Fruup commented Mar 6, 2026

🔍 Description

As the documentation already suggests (see here), I implemented a version parameter that can be attached to the download request.

What changed?

Why was this change needed?

Currently, the Supabase CDN unavoidably caches files for 1 minute. This leads to stale data being served after a file is replaced.

📸 Screenshots/Examples

download<Options extends { transform?: TransformOptions; version?: string | number }>(
  path: string,
  options?: Options,
  parameters?: FetchParameters
): BlobDownloadBuilder {
  const wantsTransformation = typeof options?.transform !== 'undefined'
  const renderPath = wantsTransformation ? 'render/image/authenticated' : 'object'
  const queryString: string = [
    // transformation
    options?.transform && this.transformOptsToQueryString(options.transform),
    // versioning
    options?.version != null && `_v=${encodeURIComponent(options.version)}`,
  ]
    .filter(Boolean)
    .join('&')
  const _path = this._getFinalPath(path)
  const downloadFn = () =>
    get(
      this.fetch,
      `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ''}`,
      {
        headers: this.headers,
        noResolveJson: true,
      },
      parameters
    )
  return new BlobDownloadBuilder(downloadFn, this.shouldThrowOnError)
}

🔄 Breaking changes

  • This PR contains no breaking changes

📋 Checklist

  • I have read the Contributing Guidelines
  • My PR title follows the conventional commit format: <type>(<scope>): <description>
  • I have run npx nx format to ensure consistent code formatting
  • I have added tests for new functionality (if applicable)
  • I have updated documentation (if applicable)

📝 Additional notes

@Fruup Fruup requested review from a team as code owners March 6, 2026 10:47
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 9709aeca-6c53-469b-a4d1-5f9cff1339c3

📥 Commits

Reviewing files that changed from the base of the PR and between c338e2f and 4e1747e.

📒 Files selected for processing (1)
  • packages/core/storage-js/src/packages/StorageFileApi.ts

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • File downloads now support an optional version parameter, enabling users to download and access specific versions of their stored files.
  • Improvements

    • Refined query string construction and URL formatting to properly handle multiple optional parameters in download requests, ensuring consistent behavior whether or not additional options are specified.

Walkthrough

The download method in the StorageFileApi class has been extended to accept an optional version parameter as part of the options object. The version value (string or number) is serialized into the query string as _v and appended to the request URL. The method unifies query string construction from both transformation and version parameters, ensuring proper URL formatting regardless of whether either parameter is provided. The changes maintain backward compatibility by treating the version parameter as optional.

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mandarini
Copy link
Copy Markdown
Contributor

Hi @Fruup, thanks for the PR! Worth noting that we recently merged #2090 which addresses the same underlying stale-cache problem, but at the HTTP fetch level (cache: 'no-store'). Your approach is actually complementary since _v busts the CDN cache specifically, so both can be needed together.

Before I can merge this, may I ask for a few things please:

  1. Tests: A unit test for the URL construction (verifying _v gets appended correctly, with and without transform options) would be straightforward to add even if the CDN behavior itself isn't testable. See packages/core/storage-js/test/storageFileApi.test.ts for examples.
  2. Expand scope: _v isn't specific to download. getPublicUrl and createSignedUrl have the same CDN caching issue and would benefit from this parameter too. Could you add it there as well for consistency?
  3. Type: Consider narrowing string | number to just string. The _v param is typically a version string or timestamp-as-string, and allowing number just adds an implicit coercion that might be surprising.

Happy to review once those are addressed! Thank you so much for contributing to Supabase! 💚

@mandarini mandarini self-assigned this Mar 9, 2026
Copy link
Copy Markdown
Contributor

@mandarini mandarini left a comment

Choose a reason for hiding this comment

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

Read my comment please

@Fruup
Copy link
Copy Markdown
Author

Fruup commented Mar 14, 2026

@mandarini Thank you for your message. I implemented your feedback :)

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 20, 2026

Open in StackBlitz

@supabase/auth-js

npm i https://pkg.pr.new/@supabase/auth-js@2153

@supabase/functions-js

npm i https://pkg.pr.new/@supabase/functions-js@2153

@supabase/postgrest-js

npm i https://pkg.pr.new/@supabase/postgrest-js@2153

@supabase/realtime-js

npm i https://pkg.pr.new/@supabase/realtime-js@2153

@supabase/storage-js

npm i https://pkg.pr.new/@supabase/storage-js@2153

@supabase/supabase-js

npm i https://pkg.pr.new/@supabase/supabase-js@2153

commit: d673f88

Copy link
Copy Markdown
Contributor

@mandarini mandarini left a comment

Choose a reason for hiding this comment

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

Great work addressing the previous feedback!!! Thank you so much! :D A few more things before this is ready to merge:

1. Trailing & in createSignedUrl

When no download or version is passed, query.toString() returns "", producing a URL like ...?token=abc&. Fix:

const queryString = query.toString()
const signedUrl = encodeURI(`${this.url}${returnedPath}${queryString ? `&${queryString}` : ''}`)

2. Same issue in createSignedUrls

? encodeURI(`${this.url}${datum.signedURL}${queryString ? `&${queryString}` : ''}`)

3. Missing test for download with version

The new test covers createSignedUrl, getPublicUrl, and createSignedUrls but not download. Since the test suite runs against real infrastructure, please add a proper integration test alongside the others:

// `download` with version
{
  const res = await storage.from(bucketName).download(uploadPath, { version })
  expect(res.error).toBeNull()
  assert(res.data)
}

Thank you so much for your patience!! :D

paths: string[],
expiresIn: number,
options?: { download: string | boolean }
options?: { download: string | boolean; version?: string }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

typescript won't be happy, setting version requires download now so it means there is test gap

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants