Tips > Data, APIs & Webhooks

Cache API Responses to Avoid Redundant Calls

If your workflow calls an API whose response does not change frequently, cache the response and serve from cache on subsequent runs.

To cache API responses in n8n, store each response in a Google Sheet, database table, or file with a timestamp, and add a time-to-live so stale entries refresh automatically. A Code node checks whether the cached value is still within its TTL; an IF node then serves the cache on a hit and calls the API only on a miss.

Why cache API responses in n8n?

If your workflow calls an API whose response does not change frequently, cache the response and serve from cache on subsequent runs. Use a Google Sheet, database table, or even a static file as your cache layer. Include a TTL (time-to-live) so stale data refreshes automatically.

Real-world example: A workflow converts prices from USD to EUR. Exchange rates change daily, but the workflow runs every time a product is viewed -- hundreds of times per day. Cache the exchange rate with a 24-hour TTL.

How do you check the cache with a TTL?

A Code node reads the stored cache entry and compares its age against the TTL, returning the cached value on a hit or flagging a refresh on a miss:

// Code node: "Check Exchange Rate Cache"
const cacheKey = 'USD_EUR';
const cacheTTLHours = 24;

// $json comes from a Google Sheets or DB lookup for the cache entry
const cacheEntry = $input.first().json;

if (cacheEntry && cacheEntry.rate && cacheEntry.cached_at) {
  const cachedAt = new Date(cacheEntry.cached_at);
  const ageHours = (Date.now() - cachedAt.getTime()) / (1000 * 60 * 60);

  if (ageHours < cacheTTLHours) {
    // Cache hit -- return cached rate
    return [{
      json: {
        rate: cacheEntry.rate,
        source: 'cache',
        cached_at: cacheEntry.cached_at,
        expires_in_hours: Math.round(cacheTTLHours - ageHours)
      }
    }];
  }
}

// Cache miss or expired -- flag for refresh
return [{
  json: {
    rate: null,
    source: 'miss',
    needs_refresh: true
  }
}];

How do you refresh and update the cache on a miss?

Use an IF node to branch: cache hit skips the API call, cache miss calls the exchange rate API and then updates the cache:

// HTTP Request node: "Fetch Fresh Rate" (only on cache miss)
{
  "method": "GET",
  "url": "https://api.exchangerate-api.com/v4/latest/USD",
  "options": { "timeout": 5000 }
}
// Code node: "Update Cache" (after fetching fresh rate)
const freshRate = $input.first().json.rates.EUR;

return [{
  json: {
    key: 'USD_EUR',
    rate: freshRate,
    cached_at: new Date().toISOString()
  }
}];
// Then write this to your Google Sheet or database
Cost savings:
  Without cache: 500 API calls/day x $0.001 = $0.50/day = $15/month
  With cache:    1 API call/day   x $0.001 = $0.001/day = $0.03/month
  Savings: 99.8%

This pattern works for any data that changes infrequently: geocoding results, company info lookups, configuration fetches, or any reference data.

Related: Use Structured Output (JSON Mode) for Parseable Responses · Configure Payload Size and Binary Data Mode for Large Files

Showcase builds

19 complete workflows from my own projects, each with its n8n workflow JSON to import. Showcase entries link the file at the end of the article.

See the showcase builds

Keep reading

190 entries grouped by topic, from first workflow to queue mode. Free, no signup.

Browse the encyclopedia

Need it built?

I design, build and run n8n systems for clients. Every engagement starts with a $1,500 diagnostic audit, credited toward the build.

Book an introductory call