Skip to main content

Access and Download Files

This guide covers file access in Postgres-Native Cloud Storage: direct downloads, signed download URLs, batch signed URLs, and public URLs.

Access methods​

MethodUse casePermission requirementNotes
download()Current user reads file contentSELECT policyReturns Blob or stream
createSignedUrl()Temporarily share a private fileSELECT permission when creating the URLURL expires
createSignedUrls()Batch-generate temporary URLsSELECT on each objectUseful for list pages
getPublicUrl()Public assetsBucket and RLS allow public readBuilds URL only; no request
HTTP API downloadBackend or cross-language integrationToken or signed URLUseful for server-side flows

Direct download​

const bucket = app.storage.from('private-files');

const { data: blob, error } = await bucket.download('user-123/resume.pdf');

if (error) {
throw error;
}

const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'resume.pdf';
a.click();
URL.revokeObjectURL(url);

If the runtime supports streams:

const { data: stream, error } = await bucket
.download('videos/demo.mp4')
.asStream();

if (error) {
throw error;
}

Signed download URL​

Use createSignedUrl() to create a temporary URL for private files:

const { data, error } = await bucket.createSignedUrl('user-123/resume.pdf', 600, {
download: 'resume.pdf',
});

if (error) {
throw error;
}

console.log(data.fullSignedURL);

The second parameter is the expiration time in seconds.

Signed URLs are for temporary sharing. For long-lived public assets, use public-read policies and getPublicUrl().

Batch signed URLs​

const { data, error } = await bucket.createSignedUrls([
'user-123/a.png',
'user-123/b.png',
], 600);

if (error) {
throw error;
}

console.log(data);

Every object is still checked by the SELECT policy. Batch signing does not bypass RLS.

Public URL​

const { data } = app.storage
.from('public-assets')
.getPublicUrl('logos/cloudbase.png');

console.log(data.publicUrl);

getPublicUrl() only builds the URL. Whether it can be accessed depends on:

  1. the bucket's public-resource configuration;
  2. a public-read SELECT policy on storage.objects;
  3. the object existing.

Public / Private recommendations​

ScenarioRecommended methodNotes
Logo, public banner, public article imagegetPublicUrl()Good for long-lived public/cacheable assets
Private user attachmentdownload()Current user reads their own file
Temporary private sharingcreateSignedUrl()Short-lived external access
Private list thumbnailscreateSignedUrls()Batch-generate short-lived links
Server-side download proxyHTTP APICentralized auth, audit, and rate limiting

CDN acceleration​

For public assets that need better performance and cache hit rates, enable CDN acceleration. The CDN behavior of Postgres-Native Cloud Storage is documented separately. See CDN Acceleration and Caching.

RLS and access operations​

Read, download, signing, and listing may all use SELECT, but the business intent can differ:

SDK operationDMLTypical permission goal
download()SELECTRead file content
createSignedUrl()SELECTCreate a temporary access URL
createSignedUrls()SELECTCreate temporary URLs in batch
getPublicUrl()May not request the serverAccess is decided when the URL is used
list()SELECTList folders or objects
info() / exists()SELECTRead metadata or existence

If you need to allow access to a known object but forbid directory listing, use storage.operation(), storage.allow_only_operation(), or storage.allow_any_operation(). See Permission management.

Cache and overwrites​

Public assets are often cached by browsers or CDNs. If you overwrite the same path, users may temporarily see old content. For details, see CDN Acceleration and Caching: Overwrites and CDN cache.

Troubleshooting​

SymptomLikely causeWhat to check
download() returns 403SELECT policy does not allow itPath, bucket_id, current auth.uid()
Failed to create signed URLCurrent user cannot read the objectQuery metadata and re-check RLS
Public URL cannot be accessedURL exists, but no public-read policyAdd SELECT TO anon for public resources
Old file is returnedCache has not refreshedUse a new path or URL version parameter

AI-friendly prompt​

Is the file public: no
Viewer: file owner or team member
Access method: create a signed download URL valid for 10 minutes
List directory: not allowed; only known object access
Path template: <uid>/<filename>