---
title: "What is an ETag? Entity tags and cache revalidation explained — warmup.rocks Glossary"
description: "The ETag header identifies a version of a resource so caches can revalidate with If-None-Match and get a 304 instead of a full download. Strong vs. weak ETags, common pitfalls, and how CDNs use them."
canonical: https://warmup.rocks/glossary/etag
---

# ETag

An **ETag** (entity tag) is an HTTP response header that identifies a specific version of a resource — typically a hash of its content. It lets browsers and CDNs ask "has this changed?" instead of re-downloading the whole thing: the client sends the ETag back in an `If-None-Match` request header, and if the version still matches, the server answers `304 Not Modified` with an empty body.

## How ETag revalidation works

The first response carries the tag:

```
HTTP/2 200
etag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
cache-control: max-age=3600
```

Once the cached copy's [TTL](https://warmup.rocks/glossary/ttl) expires, the client revalidates instead of refetching:

```
GET /style.css
if-none-match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

HTTP/2 304 Not Modified
```

A 304 costs one round trip but no body transfer — for a large asset that's the difference between milliseconds and a full re-download. CDNs use the same mechanism upstream: an edge server revalidates its stale copy against your origin and refreshes the entry's freshness without moving bytes.

## Strong vs. weak ETags

A strong ETag (`"abc123"`) promises byte-for-byte identity. A weak ETag (`W/"abc123"`) promises only semantic equivalence — the content is "the same enough" (say, a timestamp in a footer changed). Weak ETags can't be used for byte-range requests, but both work for revalidation.

## The pitfalls worth knowing

-   **Multi-server setups:** Apache's default ETag once included inode numbers, so identical files on different servers produced different tags — breaking revalidation behind load balancers. Derive ETags from content only.
-   **Compression changes bytes:** some servers emit different ETags for gzip, Brotli and identity variants of the same resource (or append `-gzip` suffixes). Combined with [Vary: Accept-Encoding](https://warmup.rocks/glossary/vary-header) this is correct behavior, but it surprises people diffing headers. Check what your stack sends with our [compression test](https://warmup.rocks/compression-test).
-   **ETag ≠ caching policy:** an ETag alone doesn't make a response cacheable — it only enables revalidation. Freshness still comes from [Cache-Control](https://warmup.rocks/glossary/cache-control).

## ETags and CDN caching

Revalidation makes expiry cheap, but the visitor still waits for the origin round trip whenever the edge copy has expired. That's why a healthy setup combines sensible ETags with a long [s-maxage](https://warmup.rocks/glossary/s-maxage) — and re-warms edge caches after purges, so real visitors hit fresh copies instead of triggering revalidations. See [our cache hit ratio guide](https://warmup.rocks/blog/cache-hit-ratio) for where revalidation fits into the bigger picture.
