CDN Acceleration and Caching
CDN acceleration, custom domains, and cache configuration in Postgres-Native Cloud Storage are shared with classic-mode Cloud Storage. This page focuses on how to design access, permissions, and caching for Postgres-Native buckets. For full configuration details, see CDN acceleration.
Access flow
After CDN acceleration is enabled, the file access path can be understood as:
User browser
│
▼
CDN edge node
│ cache hit: return directly
│ cache miss: fetch from origin
▼
CloudBase Storage API / object storage backend
The key value of CDN is to serve files from nearby edge nodes, reducing origin latency and pressure. Cache hit rate depends on whether the URL is stable, whether it can be reused by multiple users, and whether requests carry user-level authorization context.
Public buckets are more cache-friendly
Public assets do not need per-user authorization checks. When many users request the same URL, they are more likely to share the same CDN cache. Typical CDN-friendly assets include:
- logos, icons, fonts, and frontend static assets;
- public article images, product images, and campaign banners;
- public avatars and public media content.
Recommended setup:
| Item | Recommendation |
|---|---|
| Bucket | Use a dedicated public asset bucket, such as public-assets |
| Permission | Explicit public-read RLS; only trusted backend or admins can write |
| URL | Use getPublicUrl() to generate stable public URLs |
| Path | Use versioned paths, such as assets/logo.v2.png |
| Cache | Set appropriate cacheControl when uploading |
const bucket = app.storage.from('public-assets');
await bucket.upload('assets/logo.v2.png', file, {
contentType: 'image/png',
cacheControl: 'max-age=31536000',
});
const { data } = bucket.getPublicUrl('assets/logo.v2.png');
console.log(data.publicUrl);
Example public-read policy:
CREATE POLICY public_assets_read ON storage.objects
FOR SELECT TO anon, authenticated
USING (bucket_id = 'public-assets');
Public read does not mean public write. In production, avoid opening
INSERT/UPDATE/DELETEtoanon.
Private buckets usually have lower cache hit rates
Private files are typically accessed with login state, an Authorization header, or a signed URL. Even if two users access the same object, their permission context may differ, so the request is less likely to share CDN cache like a public asset.
Recommendations for private assets:
- use
download()or short-livedcreateSignedUrl(); - do not treat signed URLs as long-lived static asset URLs;
- use shorter expiration for sensitive files;
- if you need long-lived high cache hit rates, consider whether the file can be moved to a public-resource bucket with explicit public-read RLS.
| Access method | CDN friendliness | Recommendation |
|---|---|---|
getPublicUrl() | High | Public, stable, cacheable assets |
createSignedUrl() | Medium / low | Temporary sharing, not long-lived static asset URLs |
download() with login state | Low | Direct private file access |
| Backend download proxy | Depends on implementation | Centralized auth, audit, and rate limiting |
Overwrites and CDN cache
If an object path is already cached by CDN, overwriting that path may still return old content from edge nodes for a while. Similar to Supabase Storage, prefer new paths for new versions instead of frequently overwriting the same path.
Recommended:
assets/logo.v2.png
articles/123/cover-20260614.png
products/sku-001/main-<hash>.jpg
Not recommended:
assets/logo.png # frequently overwritten
articles/123/cover.jpg # frequently overwritten
Use upsert: true for fixed-path resources such as avatars only when cache delay is acceptable. Add a version parameter or update timestamp to the display URL:
const { data } = app.storage
.from('avatars')
.getPublicUrl(`${uid}/avatar.png`);
const avatarUrl = `${data.publicUrl}?v=${profile.updatedAt}`;
Cache-Control recommendations
Use cacheControl together with your path strategy:
| Asset type | Path strategy | cacheControl recommendation |
|---|---|---|
| Versioned static asset | assets/logo.v2.png | Long cache duration is acceptable |
| Article / product image | Version, timestamp, or hash in path | Long cache duration is acceptable |
| Avatar | Fixed path + URL version parameter | Medium cache duration, or business-specific |
| Private signed URL | Temporary URL | Do not rely on long-lived cache |
If the resource URL stays unchanged, avoid very long cache durations. If you need long caching, make the path itself versioned.
Decision table
| Requirement | Recommendation |
|---|---|
| Public static assets with high cache hit rate | Public Bucket + getPublicUrl() + versioned path + long cacheControl |
| Private attachment only accessible by owner | Private Bucket + download() or short-lived createSignedUrl() |
| Temporarily share a file externally | createSignedUrl() with short expiration |
| Image updates must take effect globally immediately | Use a new path and update business references; do not rely on overwriting old paths |
| Fixed avatar path | upsert is acceptable, but add a version parameter to the display URL |
AI-friendly prompt
Bucket: public-assets
Asset type: public static assets
Access method: getPublicUrl
Path strategy: versioned paths, such as assets/logo.v2.png
Cache strategy: long cache; set cacheControl on upload
Overwrite: not allowed; publish new versions with new paths
Permission: anon/authenticated can read; only service_role can write
This helps AI avoid treating private signed URLs as long-lived CDN URLs, and avoids risky designs such as overwriting the same path with long cache durations.