← Blog

Claude API Response Caching Strategy with Redis

2026-09-26 · 6 min read · SubToAPI Team

If you're calling the Claude API in production, chances are a meaningful chunk of your requests are duplicates or near-duplicates: the same system prompt, the same few-shot examples, similar user questions asked minutes apart. A Redis caching layer sits in front of your Claude calls, returns identical responses for identical inputs instantly, and cuts both latency and token spend. This article walks through how to design that layer: what to hash as a cache key, how to pick TTLs, how to handle streaming, and where caching breaks down.

The core idea is simple: before calling the Claude API, compute a deterministic hash of everything that affects the output (model, system prompt, messages, temperature, tools), check Redis for that hash, and only call the API on a miss. The hard part is deciding what counts as "the same request" and how long a cached answer stays valid for your use case.

Why cache Claude responses at all

Three reasons dominate in practice:

Caching does not replace prompt caching features built into the model provider itself — Redis caching happens at the application layer, before the request ever reaches the API, and is orthogonal to any server-side prompt caching Claude might apply internally.

Designing the cache key

The cache key must capture everything that determines the output. A naive key on just the user's message will cause bugs the moment you change your system prompt or model version.

const crypto = require('crypto');

function buildCacheKey({ model, system, messages, temperature, tools }) {
  const payload = JSON.stringify({ model, system, messages, temperature, tools });
  const hash = crypto.createHash('sha256').update(payload).digest('hex');
  return `claude:resp:${hash}`;
}

Notes on this:

Basic read-through cache with Redis

A read-through pattern is the simplest to reason about: check cache, call the API on miss, write the result back.

const redis = require('redis').createClient();
await redis.connect();

async function getClaudeResponse(request) {
  const key = buildCacheKey(request);
  const cached = await redis.get(key);
  if (cached) return JSON.parse(cached);

  const response = await fetch('https://api.subtoapi.app/v1/messages', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SUBTOAPI_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(request)
  }).then(r => r.json());

  await redis.set(key, JSON.stringify(response), { EX: 3600 });
  return response;
}

This works well for deterministic, non-streaming calls: classification tasks, structured extraction, fixed-answer FAQ bots. See /docs/messages for the request shape this hashes against.

Handling streaming responses

Streaming complicates caching because you're not caching one payload, you're caching a sequence of chunks. Two approaches work in practice:

  1. Cache the final assembled text, then on a cache hit, replay it as a synthetic stream (chunk it yourself and emit SSE-style events) so your frontend code doesn't need to know whether it was a live stream or a cached one.
  2. Only cache non-streaming calls and disable caching entirely for streamed conversational turns, since those are usually more varied anyway (real conversations rarely repeat verbatim). This is the simpler and more common choice.

If you're building on SubToAPI, streaming and non-streaming both go through the same /v1/messages endpoint (see /docs/streaming), so you can make this decision per-request based on whether the call is a good caching candidate — short, deterministic, high-repeat traffic — rather than an architectural constraint.

Choosing TTLs

TTL should reflect how quickly the "correct" answer for a given input changes:

A practical middle ground is a short default TTL (5–15 minutes) with an explicit longer TTL only for endpoints you've manually reviewed as safe to cache longer.

Cache invalidation

Because the key is a hash of full request content, most invalidation problems solve themselves — change the system prompt, get a new key, old cached answers simply age out unused. The two invalidation triggers worth building explicit handling for:

When not to cache

Skip caching for creative or conversational generation where variation is the point, for any call that includes user-specific PII you shouldn't be storing in Redis without encryption, and for tool-use requests where the tool's return value (not just the prompt) determines correctness — caching those risks serving stale tool results dressed up as fresh model output (see /docs/tools for how tool round-trips work).

Combine caching with retry and fallback logic upstream, and route your actual API calls through a service like SubToAPI so you get per-key usage metadata to verify your cache hit rate is actually reducing billed requests, not just adding latency without saving money. You can check this on the /pricing page relative to your current request volume, and get started at /signup with a free trial to test the setup on real traffic. The /docs/quickstart guide covers the basic request format this whole caching layer wraps around.

questions

Does caching Claude responses affect answer quality? Only if you cache non-deterministic calls. At temperature 0, cached answers are byte-identical to what the API would return, so quality is unaffected — the risk is caching stale or context-dependent answers too long.

Should I cache at the HTTP layer or the application layer? Application layer, using a hash of the full request payload as the key. HTTP-layer caching (e.g., a reverse proxy) doesn't understand which parts of a POST body matter for correctness and will either over-cache or under-cache.

How do I measure whether Redis caching is actually saving money? Track cache hit rate against your API usage dashboard over the same period. If you're using SubToAPI, per-key usage metadata makes it straightforward to compare requests made versus requests you'd expect without caching.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →