Caching & ETags
Automatic ETag-based caching for GET, LIST, and VIEW responses.
Quickback APIs include automatic ETag support on all read endpoints. This lets clients and edge caches avoid re-transferring unchanged data, reducing latency and bandwidth.
How it works
-
Every GET, LIST, and VIEW response includes a weak ETag header computed from the JSON body:
ETag: W/"a1b2c3d4e5f60718" -
On subsequent requests, the client sends the ETag back:
If-None-Match: W/"a1b2c3d4e5f60718" -
If the data hasn't changed, the server returns
304 Not Modifiedwith no body — saving bandwidth and parse time. -
If the data has changed, the server returns the full response with a new ETag.
Which endpoints support ETags
| Endpoint | ETag | Notes |
|---|---|---|
GET / (list) | Yes | |
GET /:id (get) | Yes | |
GET /views/:name (view) | Yes | |
POST / (create) | No | Mutations don't cache |
PUT /:id (update) | No | |
DELETE /:id (delete) | No | |
| Actions | No | Side-effectful |
| Batch operations | No | Mutations |
Security
ETags are computed after all security pillars are applied (Firewall, Access, Guards, Masking). This means:
- Different users with different masking rules get different ETags
- Firewall-scoped data produces ETags specific to that scope
- There is no risk of leaking data across users via cached ETags
Response headers
When ETags are enabled, GET responses include:
Content-Type: application/json
ETag: W/"a1b2c3d4e5f60718"
Cache-Control: no-cacheCache-Control: no-cache means the browser (or edge cache) must revalidate on every request, but can use the cached response if the ETag matches. This is the correct behavior for authenticated APIs — data is always fresh, but unchanged responses avoid re-transfer.
Client usage
fetch API
// First request
const res = await fetch("/api/v1/jobs");
const etag = res.headers.get("ETag");
const data = await res.json();
// Subsequent request with ETag
const res2 = await fetch("/api/v1/jobs", {
headers: { "If-None-Match": etag },
});
if (res2.status === 304) {
// Data hasn't changed, use cached version
} else {
const freshData = await res2.json();
}Axios / ky / other clients
Most HTTP clients handle 304 responses automatically when configured with an interceptor or cache adapter.
Configuration
ETags are enabled by default. To disable them, set etag.enabled to false in quickback.config.ts:
export default defineConfig({
name: "my-app",
// ...
etag: {
enabled: false,
},
});When disabled, GET responses use standard c.json() with no ETag headers or 304 handling.
| Option | Default | Description |
|---|---|---|
enabled | true | Include ETag headers on GET/LIST/VIEW responses |
Technical details
- Weak ETags (
W/"...") — semantically equivalent responses, not byte-identical - SHA-256 truncated to 16 hex chars — sufficient for collision avoidance, keeps the header small
- Web Crypto API — uses
crypto.subtle.digest(), available in Cloudflare Workers and Node 18+ - No dependencies — zero additional packages required