Hi Supabase team. I am trying to understand whether this is expected behavior or a Smart CDN issue.
I am serving images from a private Storage bucket with signed URLs. The same exact signed URL is reused across requests. Based on the Smart CDN docs, I expected the first request for that signed URL to be a MISS, and later requests for the same exact URL/token to become HITs.
What I see instead is:
GET 1: cf-cache-status: MISS
GET 2: cf-cache-status: REVALIDATED
GET 3: cf-cache-status: REVALIDATED
GET 4: cf-cache-status: REVALIDATED
The important detail is that I am not generating a new signed URL each time. It is the same URL, same token, same object.
I also tried uploading the object with a very aggressive cache control value:
Cache-Control: public, s-maxage=31536000, max-age=31536000, immutable
The object metadata stores that value correctly, but the signed private URL still revalidates on every request. A HEAD request to the signed URL returns cache-control: no-cache.
Here is the shape of the repro I used, with the actual project URL/token omitted:
# Upload an image to a private bucket with immutable cache metadata.
curl -X POST \
"$SUPABASE_URL/storage/v1/object/my-private-bucket/test.avif" \
-H "Authorization: Bearer $SERVICE_ROLE_KEY" \
-H "apikey: $SERVICE_ROLE_KEY" \
-H "Content-Type: image/avif" \
-H "Cache-Control: public, s-maxage=31536000, max-age=31536000, immutable" \
-H "x-upsert: false" \
--data-binary @test.avif
# Create one signed URL with a long expiry.
curl -X POST \
"$SUPABASE_URL/storage/v1/object/sign/my-private-bucket/test.avif" \
-H "Authorization: Bearer $SERVICE_ROLE_KEY" \
-H "apikey: $SERVICE_ROLE_KEY" \
-H "Content-Type: application/json" \
-d '{"expiresIn":1576800000}'
# Then reuse the returned signedURL exactly.
for i in 1 2 3 4; do
curl -sS -o /dev/null -D - "$SIGNED_URL" \
-w "attempt=$i ttfb=%{time_starttransfer} total=%{time_total}\n" \
| grep -Ei '^(HTTP/|cf-cache-status:|age:|cache-control:|etag:|expires:|last-modified:|attempt=)'
done
Observed headers on repeated GETs look like this:
HTTP/2 200
cf-cache-status: REVALIDATED
etag: "..."
expires: <far future date based on signed URL expiry>
last-modified: <object timestamp>
A HEAD request to the same signed URL returns:
HTTP/2 200
cf-cache-status: MISS
cache-control: no-cache
etag: "..."
expires: <far future date based on signed URL expiry>
last-modified: <object timestamp>
For comparison, a public bucket object on the same project behaves as expected:
cf-cache-status: HIT
age: <increasing>
cache-control: 31536000
So the CDN is working generally; the behavior seems specific to private signed object URLs.
I found this older issue, which says signed URLs missing cache was expected at the time: supabase/supabase#23406
But the current Smart CDN docs now say signed URL responses are cached at the edge and that subsequent requests using the exact same signed URL should receive a cache hit: https://supabase.com/docs/guides/storage/cdn/smart-cdn#signed-urls-and-cdn-caching
Is REVALIDATED on every request expected for private signed URLs, even when the same signed URL is reused and the object has immutable cache metadata? Or should these eventually become HIT responses?
If there is any extra metadata or signed URL option needed for immutable assets that never change, I would be happy to try it. I could not find a documented way to override Cache-Control on the signed URL response itself.
Hi Supabase team. I am trying to understand whether this is expected behavior or a Smart CDN issue.
I am serving images from a private Storage bucket with signed URLs. The same exact signed URL is reused across requests. Based on the Smart CDN docs, I expected the first request for that signed URL to be a MISS, and later requests for the same exact URL/token to become HITs.
What I see instead is:
The important detail is that I am not generating a new signed URL each time. It is the same URL, same token, same object.
I also tried uploading the object with a very aggressive cache control value:
The object metadata stores that value correctly, but the signed private URL still revalidates on every request. A HEAD request to the signed URL returns
cache-control: no-cache.Here is the shape of the repro I used, with the actual project URL/token omitted:
Observed headers on repeated GETs look like this:
A HEAD request to the same signed URL returns:
For comparison, a public bucket object on the same project behaves as expected:
So the CDN is working generally; the behavior seems specific to private signed object URLs.
I found this older issue, which says signed URLs missing cache was expected at the time: supabase/supabase#23406
But the current Smart CDN docs now say signed URL responses are cached at the edge and that subsequent requests using the exact same signed URL should receive a cache hit: https://supabase.com/docs/guides/storage/cdn/smart-cdn#signed-urls-and-cdn-caching
Is
REVALIDATEDon every request expected for private signed URLs, even when the same signed URL is reused and the object has immutable cache metadata? Or should these eventually becomeHITresponses?If there is any extra metadata or signed URL option needed for immutable assets that never change, I would be happy to try it. I could not find a documented way to override
Cache-Controlon the signed URL response itself.