301 vs. 302 Redirects in URL Shorteners: Speed, SEO, and Caching Best Practices


TL;DR (for busy engineers and marketers)

  • Use 301 for links whose destination is meant to be permanent (evergreen pages, canonical product URLs, app store pages that won’t change). It helps consolidate SEO signals and is heavily cacheable, which reduces redirect latency over time.
  • Use 302 for links whose destination might change or depends on rules (geo/device targeting, A/B testing, campaigns that rotate offers, “maintenance mode”, or temporary rewrites). It prevents long-lived caching from locking in a target you’ll soon replace.
  • Speed: The fastest redirect is the one you don’t need—but when you do, minimize round-trips (DNS, TLS, request) and let caches work for you. A 301 cached at the browser or edge makes future clicks effectively free (no origin hit).
  • Caching: 301 is typically cached aggressively (often “forever” by browsers) unless you deliberately counteract it. 302 is not reliably cached unless you add explicit Cache-Control and/or CDN rules.
  • SEO: Modern search engines generally pass link equity through both 301 and 302 over time, but index selection and canonicalization align most predictably with 301 for permanent moves.
  • Rule of thumb:
    • Static, long-term links → 301
    • Dynamic, rule-based, or experimental links → 302
    • Migrating or unsure? Start with 302, monitor, then upgrade to 301 once stable.

Table of Contents

  1. What Redirects Do Inside a Shortener
  2. HTTP Status Fundamentals (301 vs. 302, plus 307/308)
  3. The SEO Angle: Equity, Canonicalization, and Indexing
  4. The Caching Angle: Browser, CDN, and Intermediaries
  5. The Speed Angle: Where Latency Comes From and How to Cut It
  6. Decision Framework: When to Choose 301 vs. 302
  7. Advanced: 307 and 308 in Shorteners (and when they help)
  8. Architecture Patterns for Shorteners
  9. Implementation Recipes (NGINX, Apache, Express/Node, Go, Cloudflare Workers, Kubernetes Ingress, Varnish/Fastly/CloudFront)
  10. Caching Strategies at the Edge (and mistakes to avoid)
  11. Migration Playbooks (302→301, 301 rollback, mass retargeting)
  12. Analytics & Measurement (and avoiding sampling errors)
  13. Troubleshooting Guide (stuck caches, mobile deep links, open redirects, UTM quirks)
  14. FAQs
  15. Final Checklist
  16. Optional: SEO Schema (FAQ) to embed with the article
  17. Conclusion

1) What Redirects Do Inside a Shortener

A link shortener receives a short hostname and slug (e.g., example.co/xYz12) and returns a 3xx response that points to a longer target URL. This seems trivial, but it sits at the intersection of network performance, caching behavior, and search engine processing. Choosing between 301 (Moved Permanently) and 302 (Found / Temporary) determines:

  • How future clients (browsers, bots, CDNs) cache the redirect.
  • Whether search engines fold signals (rank, anchors) into the destination.
  • How quickly repeat visitors skip the origin and get served from browser or edge cache.
  • How safe it is to retarget or run rules (geo/device/AB tests) without caches “remembering” an old choice.

Shorteners are often used for marketing (UTMs, tracking), governance (brand consistency), resilience (quickly retarget broken links), and developer productivity (one stable short link in code or PDFs that can be changed later). That mix is why understanding 301 vs. 302 is mission-critical.


2) HTTP Status Fundamentals (301 vs. 302, plus 307/308)

301 Moved Permanently

  • Signals a permanent move.
  • Strong caching semantics: many browsers cache indefinitely (or long enough to feel “forever”).
  • Historically allowed changing the request method (POST → GET), though modern clients increasingly follow RFCs more strictly.

302 Found (Temporary)

  • Signals a temporary move.
  • Caching is ambiguous: by default, many clients do not cache 302 unless accompanied by explicit Cache-Control or Expires. Some intermediaries may cache short periods, others won’t.
  • Safer for dynamic routing and scenarios where the destination may change or depend on context.

Related codes worth knowing:

  • 307 Temporary Redirect: temporary and preserves the HTTP method and body (no POST→GET switch).
  • 308 Permanent Redirect: permanent and preserves the HTTP method and body (a more modern version of 301 with stricter semantics).
  • In shorteners, 307/308 are useful when you must guarantee method preservation—less common for simple GET redirects, but important for API traffic or web apps that redirect after non-GET operations.

3) The SEO Angle: Equity, Canonicalization, and Indexing

Modern search engines are smarter than they were a decade ago:

  • Equity (PageRank/link signals): Search engines generally pass link equity through both 301 and 302. Over time, a stable 302 may be treated as a soft permanent move. That said, the most predictable consolidation of signals (and index selection) still aligns with 301/308 for permanent moves.
  • Canonicalization: Search engines choose a canonical URL when duplicates exist. A 301 is a strong signal that the destination is canonical. A 302 says “this is temporary,” which can lead the engine to keep the source URL in the index.
  • Index freshness: If you’re migrating content or consolidating domains, a clean 301 path (no chains, no loops) helps search engines update their index and carry signals forward.
  • Redirect chains: Multiple hops (shortener → tracking → canonical) add latency and can complicate crawling. Prefer one hop whenever possible (shortener → final canonical).
  • UTM parameters: Search engines largely ignore UTM parameters for ranking; but those parameters create distinct URLs from a caching perspective. Redirect choice affects whether caches treat each UTM variant as unique or collapse them.

SEO best practice summary:

  • Use 301/308 for permanent, stable destinations.
  • Use 302/307 for testing, temporary, or rule-based behaviors.
  • Avoid chains; if you must chain, keep it to two hops max and stabilize quickly.
  • Keep HTTP to HTTPS upgrades out of the critical path (use HSTS) to remove an extra hop.

4) The Caching Angle: Browser, CDN, and Intermediaries

Caching is where 301 vs. 302 really diverge.

4.1 Browser caching

  • 301: Often cached persistently. Once a browser “learns” a 301, future requests to the short URL skip network and go straight to the destination, or hit fewer layers (e.g., a stored redirect map). That’s blazing fast for repeat visitors—but dangerous if you change your mind.
  • 302: Typically not cached by browsers unless specified (e.g., Cache-Control: max-age=60). This makes 302 ideal for dynamic routing and campaigns that may change tomorrow.

4.2 Shared/intermediate caching (CDNs, proxies, ISP caches)

  • Intermediaries can cache both 301 and 302 if you direct them to. However, the default bias is:
    • 301 → cacheable by default (long TTLs at the edge are common).
    • 302 → cache only when you ask for it (page rules / response headers).
  • If you operate a shortener on a CDN/edge runtime, you can explicitly set TTLs and cache key strategy (e.g., ignore utm_* in cache key, or include Accept-Language for geo). Combining the right status code with the right cache key is the secret sauce.

4.3 Search engine caches

  • Crawlers store redirect mappings. A long-lived 301 accelerates crawling and reduces wasted fetches. A 302 may be revisited more often to detect changes (which is good for experiments).

4.4 Headers that influence caching

  • Cache-Control: max-age, s-maxage (shared caches), no-store, no-cache, must-revalidate, immutable.
  • Expires: legacy absolute expiry timestamp.
  • Vary: creates separate cache entries for different request headers (e.g., Vary: User-Agent for device targeting).
  • Age: time since the response was cached at an intermediary.
  • ETag/Last-Modified: less relevant for redirects (since there’s no body), but some stacks emit them anyway.

Rule of thumb:

  • If the destination is static, leverage 301 plus a long edge TTL.
  • If the destination is dynamic, use 302 and only cache at the edge when you’re deliberately pinning rules for a short period (e.g., 60–300s) to offload origin.

5) The Speed Angle: Where Latency Comes From and How to Cut It

A redirect click includes several latency components:

  1. DNS resolution for the short domain
  2. TLS handshake (and ALPN/H2/H3 negotiation)
  3. Request → 3xx response from your edge or origin
  4. Follow-up request to the destination (which repeats DNS/TLS unless already warm)

Your job is to remove entire steps (via caching) and shrink the steps you keep.

Tactics:

  • Keep it at the edge. Serve redirects from a global edge network so the first hop is physically close.
  • Cache 301s aggressively for stable links; subsequent clicks become near-instant.
  • For 302s, consider a short edge TTL (e.g., 60s) to absorb spikes while still allowing quick changes.
  • Reduce hops: Avoid chains (shortener → tracker → destination). If you must add parameters for tracking, bake them directly on the 3xx Location once.
  • HSTS (HTTP Strict Transport Security): Preload your domain; this removes the http → https hop entirely.
  • QUIC/HTTP/3 and 0-RTT (where available) reduce handshake cost.
  • Connection reuse: If the shortener and the final destination share a CDN, the client may reuse warm connections more often (not guaranteed, but architecting on the same edge provider can help).
  • CNAME flattening or apex aliasing**:** Ensure your short domain resolves without extra lookups or slow chains.

Real-world guidance: Properly cached 301s can drop the initial redirect hop to ~1–10ms at the edge (plus network RTT). Uncached origin-served redirects often cost 50–200ms (or more) per click, multiplied by every hop and every visitor.


6) Decision Framework: When to Choose 301 vs. 302

Use 301 (or 308) when:

  • The link is stable and unlikely to change (evergreen marketing pages, docs, canonical product pages, app store listing URLs).
  • You want strong caching to reduce cost and latency.
  • You want search engines to consolidate signals predictably at the target.
  • You’re decommissioning old paths or consolidating content permanently.

Use 302 (or 307) when:

  • The destination depends on rules (geo/device/time, A/B testing, language negotiation).
  • You expect to change the target (campaigns, temporary offers).
  • You’re validating a migration—start with 302 to watch behavior, then switch to 301 when confident.
  • You need to avoid long-lived caches that would lock in an outdated target.

Quick table:

ScenarioRecommendedWhy
Evergreen blog post, whitepaper, product page301Fast via caching; consolidates SEO signals
App Store / Play Store links301Stable target, caching helps mobile performance
Geo/device targeting (US vs. EU offer pages)302 + VaryAvoid long-lived caches; instruct edge on varied cache keys
A/B tests / multivariate302 (optionally 307)Temporary, don’t lock in
Campaign rotation (weekly/monthly)302Change targets without cache fighting
Temporary maintenance bypass302Revert easily
Domain migration (permanent)301 or 308Strong permanent signal

7) Advanced: 307 and 308 in Shorteners (and when they help)

  • 307 Temporary Redirect: Guarantees method preservation. Useful for app flows (e.g., redirect after a POST) and for strict clients where you cannot risk method changes.
  • 308 Permanent Redirect: Permanent + method preservation. A good modern alternative to 301 for APIs and web apps that send non-GET requests and may encounter strict clients.

In the typical link-shortening GET world, 301/302 suffice. Reach for 307/308 if you’re handling non-GET flows or want stricter semantics to avoid surprises.


8) Architecture Patterns for Shorteners

  1. Static mapping at the edge
    • Key/Value (KV) store or CDN config maps slug → URL.
    • 301 for stable links; 302 only for temporary.
    • Pros: blazing fast; minimal origin cost.
    • Cons: more operational effort to push changes globally.
  2. Rules engine with dynamic routing
    • Evaluate geo/IP, device, language, time-window, AB bucket.
    • Default to 302; add Vary and cache key segmentation for performance.
    • Consider short TTLs (30–300s) at the edge to reduce origin hits.
  3. Hybrid
    • Stable slugs pinned as 301 in KV.
    • Slugs flagged as “dynamic” use 302 via a rules function.
    • Add SLA: any slug with >N daily clicks must be at the edge, never origin-served.
  4. Analytics pipeline
    • Emit 3xx status, redirect time, target as log events.
    • Sample if needed, but keep high-value slugs unsampled.
    • Avoid analytics calls that add another network hop before the redirect; make the 3xx the first response.

9) Implementation Recipes

9.1 NGINX (edge or origin)

Permanent (301):

server {
    listen 443 ssl http2;
    server_name s.example.co;

    # HSTS to remove http->https hop
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    location = /promo {
        return 301 https://www.example.com/evergreen-offer;
    }

    # for dynamic slugs, pass to app
    location / {
        proxy_pass http://shortener_app;
    }
}

Temporary (302) with short cache at edge:

location = /daily-offer {
    add_header Cache-Control "public, max-age=60, s-maxage=60";
    return 302 https://www.example.com/offers/today;
}

Logging useful metrics:

log_format redirect '$remote_addr - $request_time - $status - $request - $sent_http_location';
access_log /var/log/nginx/shortener.access.log redirect;

9.2 Apache (.htaccess)

# 301
Redirect 301 /docs https://www.example.com/resources/documentation

# 302 with cache
<IfModule mod_headers.c>
  <Location "/flash-sale">
    Header set Cache-Control "public, max-age=120"
  </Location>
</IfModule>
Redirect 302 /flash-sale https://www.example.com/deals/today

9.3 Express (Node.js)

const express = require('express');
const app = express();

app.get('/permanent', (req, res) => {
  res.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
  res.redirect(301, 'https://www.example.com/evergreen');
});

app.get('/ab', (req, res) => {
  const bucket = Math.random() < 0.5 ? 'A' : 'B';
  res.set('Cache-Control', 'no-store'); // do not cache decision
  res.redirect(302, `https://www.example.com/landing-`);
});

app.listen(8080);

9.4 Go (net/http)

http.HandleFunc("/p", func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
    http.Redirect(w, r, "https://www.example.com/evergreen", http.StatusMovedPermanently) // 301
})

http.HandleFunc("/geo", func(w http.ResponseWriter, r *http.Request) {
    // pseudo geo logic
    var dest string
    if r.Header.Get("X-Country") == "DE" {
        dest = "https://www.example.de/angebot"
    } else {
        dest = "https://www.example.com/offer"
    }
    w.Header().Set("Vary", "X-Country")
    w.Header().Set("Cache-Control", "public, max-age=120, s-maxage=120")
    http.Redirect(w, r, dest, http.StatusFound) // 302
})

9.5 Cloudflare Workers (edge runtime)

export default {
  async fetch(req) {
    const url = new URL(req.url);
    // simple KV-based permanent redirect
    if (url.pathname === '/app') {
      return new Response(null, {
        status: 301,
        headers: { 'Location': 'https://apps.apple.com/app/your-app',
                   'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload' }
      });
    }

    // dynamic/rule-based: 302 with short TTL at edge
    if (url.pathname === '/daily') {
      const dest = await getTodayOffer(); // your logic
      return new Response(null, {
        status: 302,
        headers: {
          'Location': dest,
          'Cache-Control': 'public, s-maxage=60, max-age=60',
          'Vary': 'CF-IPCountry'
        }
      });
    }

    return new Response('Not found', { status: 404 });
  }
}

9.6 Kubernetes Ingress (NGINX Ingress Controller)

HTTP→HTTPS via annotation (avoid extra app logic):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shortener
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
  tls:
  - hosts: [ "s.example.co" ]
    secretName: s-example-tls
  rules:
  - host: s.example.co
    http:
      paths:
      - path: /permanent
        pathType: Prefix
        backend:
          service:
            name: perm-redirect-svc
            port:
              number: 80

Permanent redirect with configuration-snippet:

metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($request_uri ~ "^/permanent$") {
        return 301 https://www.example.com/evergreen;
      }

Temporary redirect with per-location cache headers:

metadata:
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |
      location = /flash {
        add_header Cache-Control "public, max-age=120, s-maxage=120";
        return 302 https://www.example.com/deals/today;
      }

9.7 Varnish / Fastly (VCL style)

sub vcl_recv {
  if (req.url.path == "/app") {
    set req.http.X-Redirect-To = "https://apps.apple.com/app/your-app";
    return (hash);
  }
}

sub vcl_hash {
  if (req.url.path == "/daily") {
    hash_data(req.http.Fastly-GeoIP-Country-Code);
  }
}

sub vcl_deliver {
  if (req.http.X-Redirect-To) {
    set resp.status = 301;
    set resp.http.Location = req.http.X-Redirect-To;
    set resp.http.Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload";
    return (deliver);
  }
}

9.8 AWS CloudFront (Function@Edge / Lambda@Edge idea)

  • Use a viewer request function to map path → Location.
  • For permanent: set status 301 and add long Cache-Control on the 3xx itself via response function (or cache behavior TTLs).
  • For dynamic: issue 302 and set Vary (e.g., CloudFront-Viewer-Country) + short TTLs.

10) Caching Strategies at the Edge (and mistakes to avoid)

Good strategies:

  • 301 + long TTL for permanent slugs inside KV.
  • 302 + short TTL (30–300s) for dynamic slugs to reduce origin load while allowing quick changes.
  • Normalize cache keys: strip utm_*, fbclid, gclid if they don’t alter the redirect decision.
  • Use Vary only when needed (country/device). Every Vary value multiplies cache storage and lowers hit ratio.
  • Backstop TTLs: Protect origin with a minimum TTL in case your app forgets to set headers.

Common mistakes:

  • Accidental long caching of 302 that locks in A/B buckets for too long.
  • Returning 301 for a campaign that you plan to change next week—browsers and edges will memorize it.
  • Redirect chains (short→tracking→tracking→dest). Every hop costs latency and reliability.
  • Forgetting HSTS, forcing an extra http→https hop.
  • Using no-store everywhere “just to be safe,” which throws away huge performance wins.

11) Migration Playbooks

11.1 Start with 302, upgrade to 301

  1. Launch the slug with 302.
  2. Observe: click-through, bounce, geo/device distribution, bot ratio.
  3. If the destination is stable for N days (choose your comfort: 7–30), switch to 301.
  4. Announce a long TTL for the 301 at the edge to reap speed/cost benefits.

11.2 301 rollback (in emergencies)

  • You pushed 301 but need a new destination. Browsers might have cached it.
  • Immediate fix: Change the slug to 302 with a new destination and add Cache-Control: no-store temporarily.
  • Communicate: If critical, publish a note to affected users (e.g., app deep link changed).
  • Longer term: Avoid 301 on slugs likely to change; mark them as “dynamic” in your CMS.

11.3 Consolidating domains

  • Map old domain slugs to new domain slugs with 301.
  • Ensure a single hop: old.co/slug → new.co/final (no intermediate tracking).
  • Keep the old domain live long enough for crawlers and users to update caches.

12) Analytics & Measurement

  • Log the 3xx: status code, request time, edge location/POP, chosen destination, and decision factors (geo, device, AB bucket).
  • Avoid client-side beacons before the redirect—they add latency. Prefer server logs or edge logs.
  • Sampling: If volume is huge, sample after counting total clicks to avoid skew.
  • Attribution: If you add UTMs on the Location, do it once (shortener → destination) and avoid adding a second redirect just to set parameters.

Key metrics to watch:

  • Redirect TTFB (at edge)
  • Hops per click (aim for 1)
  • Edge cache hit ratio by slug and code (301 vs. 302)
  • Origin QPS for redirect endpoints
  • Error rates (4xx/5xx) that derail redirects

13) Troubleshooting Guide

Problem: “Users still hit the old target after we changed it.”

  • Likely a cached 301 in browsers or an edge with a long TTL.
  • Temporary fix: serve 302 with Cache-Control: no-store for a period. Consider changing the path (a new slug) for critical cases.

Problem: “Our AB test results are inconsistent across regions.”

  • Ensure the redirect response sets Vary for any header you key on (e.g., country).
  • Reduce 302 edge TTL if users are being pinned too long to one variant.

Problem: “Redirect chain is slow.”

  • Collapse parameters into a single 3xx.
  • Ensure HSTS is enabled to remove http→https.
  • Put the redirect logic on the edge, not origin.

Problem: “Open redirect vulnerability reported.”

  • Validate slug targets against allowlists (domains/paths/protocols).
  • Never use untrusted query parameters to compose Location.

Problem: “UTM data missing at analytics vendor.”

  • Confirm the shortener appends UTMs directly in the 3xx Location.
  • Avoid another hop at the destination that might drop or rewrite parameters.

Problem: “App deep links fail on some devices.”

  • For iOS/Android, consider app links/universal links and provide fallback web targets.
  • Use 301 for stable app store links; use 302 for device-specific routing.

14) FAQs

Q: Do 301s always pass more SEO equity than 302s?
A: Both can pass signals; 301/308 is more explicit for permanent moves and tends to produce more predictable canonicalization. When in doubt or migrating permanently, use 301/308.

Q: Can I cache 302s at the edge?
A: Yes—if you set Cache-Control (and/or CDN rules). Use short TTLs to prevent stale routing.

Q: Is 308 better than 301?
A: For GET redirects in shorteners, they’re functionally similar. 308 preserves method, which is useful for non-GET workflows.

Q: How do I undo a 301?
A: You can’t reliably “uncache” a user’s browser. Use new slugs, or temporarily switch to 302 with no-store, and allow time for caches to refresh.

Q: Should I always strip UTM parameters from cache keys?
A: Often yes for shorteners—unless UTMs affect the decision logic. Stripping them increases hit ratio and performance.

Q: Is a 302 slower than a 301?
A: The status code itself isn’t slower; the caching behavior is what affects speed. Cached 301s are typically much faster on repeat visits.


15) Final Checklist

  • Decide scope: Is the destination permanent (301) or dynamic (302)?
  • Edge first: Run redirect logic on a global edge, not origin.
  • HSTS on: Remove http→https redirect.
  • One hop: Shortener → final URL.
  • Cache smart:
    • 301: long TTL, strip UTMs from cache key.
    • 302: short TTL or no-store if highly dynamic; add Vary when needed.
  • Log essentials: status, latency, chosen target, decision inputs.
  • Security: validate targets, prevent open redirects.
  • SEO: use 301/308 for permanent moves; avoid chains.
  • Ops: document rollback steps for accidental 301s.

16) Optional: SEO Schema (FAQ)

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [{
    "@type": "Question",
    "name": "Do 301s always pass more SEO equity than 302s?",
    "acceptedAnswer": {
      "@type": "Answer",
      "text": "Both 301 and 302 can pass signals. 301/308 is the safest bet for permanent moves and predictable canonicalization."
    }
  },{
    "@type": "Question",
    "name": "Can I cache 302s at the edge?",
    "acceptedAnswer": {
      "@type": "Answer",
      "text": "Yes. Set Cache-Control and/or CDN rules. Use short TTLs to prevent stale routing."
    }
  },{
    "@type": "Question",
    "name": "Is 308 better than 301?",
    "acceptedAnswer": {
      "@type": "Answer",
      "text": "For typical shortener GET redirects, they’re similar. 308 preserves method and is useful for non-GET flows."
    }
  },{
    "@type": "Question",
    "name": "How do I undo a 301?",
    "acceptedAnswer": {
      "@type": "Answer",
      "text": "Browsers may cache 301s long-term. Use a new slug or switch to 302 with no-store while transitioning."
    }
  }]
}
</script>

17) Conclusion

Choosing between 301 and 302 in a URL shortener is not about dogma—it’s about intent and lifecycle:

  • If your link is a stable pointer to a canonical destination, 301 (or 308) unlocks powerful caching and clearer SEO outcomes. Users enjoy faster repeat loads, your edge sees higher hit ratios, and crawlers converge on the right canonical quickly.
  • If your link is dynamic—driven by rules, experiments, or frequent campaign changes—302 (or 307) keeps you agile, prevents long-lived caches from freezing old decisions, and ensures you can pivot instantly.
  • Beyond the status code, performance comes from where the decision happens (edge vs. origin), how you cache (TTLs, cache keys, Vary), and how many hops you force the user to take.

Master these levers—status code semantics, edge caching, and crawl-friendly architecture—and your shortener becomes not just a URL alias, but a high-performance routing layer that improves SEO, cuts latency, and gives your marketing and product teams the agility they need.


Appendix: Copy-Paste Snippets

Strict HSTS (once you’re fully HTTPS):

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Cache 302 briefly at the edge:

Cache-Control: public, s-maxage=120, max-age=60

Disable caching for volatile tests:

Cache-Control: no-store

Vary on country (edge provides header):

Vary: CF-IPCountry

Common redirect headers you’ll log:

  • Location
  • Cache-Control / Expires
  • Vary
  • Age (from intermediaries)

Practical Examples Recap

  • Evergreen download link301 + long TTL at edge; no UTMs in cache key.
  • Geo-offer302, Vary: Country, short TTL (60–300s).
  • AB test302 with no-store (or short TTL), AB bucket decision in edge logic.
  • Domain consolidation301, single hop, no chains.
  • Emergency change after 301 → temporary 302 + no-store and (if needed) new slug.

With these patterns and snippets, you can implement a shortener that is fast by default, SEO-safe by design, and operationally flexible when business needs change.