Composable Axios adapter enhancers for cache, throttle, and retry.
Quick Start • API • Migration • npm
axios-extensions gives you production-friendly request behavior without replacing Axios itself.
This README targets v4.x. Looking for older docs? See v3.1.7.
Migrating from v3? Read MIGRATION.md.
- Why axios-extensions
- Version & Compatibility
- Installation
- Quick Start
- API
- TypeScript Notes
- Logging
- Development
- License
- ⚡ Composable by design: stack cache, throttle, and retry in one adapter pipeline.
- 🧠 Sensible defaults: GET caching, GET-only throttling, and retry controls out of the box.
- 🧩 TypeScript-ready: request config is module-augmented for feature flags and overrides.
- 🪶 Lightweight: focused utilities with no framework lock-in.
| Enhancer | What it does | Typical use case |
|---|---|---|
cacheAdapterEnhancer |
Request-level response caching | Avoid duplicate reads for the same resource |
throttleAdapterEnhancer |
Dedupe/throttle GET requests inside a time window | Prevent burst requests during rapid UI interactions |
retryAdapterEnhancer |
Retry failed requests with global/per-request overrides | Improve resilience on flaky networks |
These enhancers are designed to be composed together on top of Axios adapters.
| If you want to... | Use |
|---|---|
| Avoid duplicate reads and reuse response results | cacheAdapterEnhancer |
| Collapse repeated GET requests in rapid bursts | throttleAdapterEnhancer |
| Survive transient network/backend failures | retryAdapterEnhancer |
| Package | Supported version |
|---|---|
| Node.js | >= 18 |
| axios | >= 1.0.0 |
axios v0.19.0 is not supported due to an Axios custom config issue: axios/axios#2207
npm i axios-extensionsyarn add axios-extensionsBrowser UMD build:
<!-- exposed as window['axios-extensions'] -->
<script src="https://unpkg.com/axios-extensions/dist/axios-extensions.min.js"></script>Compose all three enhancers in one adapter:
import axios from 'axios';
import {
cacheAdapterEnhancer,
throttleAdapterEnhancer,
retryAdapterEnhancer,
} from 'axios-extensions';
const adapter = retryAdapterEnhancer(
throttleAdapterEnhancer(
cacheAdapterEnhancer(axios.defaults.adapter!),
{ threshold: 1000 },
),
{ times: 2 },
);
export const http = axios.create({
baseURL: '/api',
adapter,
});Per-request overrides:
await http.get('/users', {
forceUpdate: true,
threshold: 3000,
retryTimes: 3,
});Common composition presets:
// 1) Cache only
const cacheOnly = cacheAdapterEnhancer(axios.defaults.adapter!);
// 2) Cache + throttle (great for list/search pages)
const cacheAndThrottle = throttleAdapterEnhancer(
cacheAdapterEnhancer(axios.defaults.adapter!),
{ threshold: 1000 },
);
// 3) Full resilience pipeline
const resilient = retryAdapterEnhancer(cacheAndThrottle, { times: 2 });When to use: cache requests (GET by default) and optionally customize cache strategy/key generation.
cacheAdapterEnhancer(adapter: NonNullable<AxiosRequestConfig['adapter']>, options?: {
cacheable?: (config: AxiosRequestConfig) => boolean | ICacheLike<any>;
keyGenerator?: (config: AxiosRequestConfig) => string;
defaultCache?: ICacheLike<AxiosPromise>;
}): AxiosAdapterDefault behavior:
- If
config.cacheis set, it is used as override - Otherwise GET requests are cached
- Default cache store is
new Cache({ ttl: 5 * 60 * 1000, max: 100 })
Common request options (module-augmented on AxiosRequestConfig):
cache?: boolean | ICacheLike<any>forceUpdate?: boolean
Example: enable cache for GET by default, but force refresh per request:
await http.get('/users', { forceUpdate: true });Example: opt-in cache only:
const adapter = cacheAdapterEnhancer(axios.defaults.adapter!, {
cacheable: config => config.cache ?? false,
});Example: cache GET + POST with a URL-only key (safe only when params/body do not affect response):
const adapter = cacheAdapterEnhancer(axios.defaults.adapter!, {
cacheable: config => config.method === 'get' || config.method === 'post',
keyGenerator: config => `${config.method}:${config.url}`,
});config.url alone is only safe when query params/body do not change response semantics. Otherwise include params and (for non-GET) data in the key.
When to use: dedupe GET requests triggered repeatedly within a short interval.
throttleAdapterEnhancer(adapter: NonNullable<AxiosRequestConfig['adapter']>, options?: {
threshold?: number;
cache?: ICacheLike<{ timestamp: number; value?: AxiosPromise }>;
}): AxiosAdapterDefault behavior:
- Only affects GET requests
- Requests within
threshold(default1000ms) reuse in-flight/previous promise - Non-GET requests pass through untouched
Request-level override:
threshold?: numberonAxiosRequestConfig
await http.get('/users', { threshold: 3000 });When to use: retry transient failures without rewriting request logic.
retryAdapterEnhancer(adapter: AxiosAdapter, options?: {
times?: number;
}): AxiosAdapterDefault behavior:
- Retries failed requests up to
times(default2) - Per-request override via
retryTimes?: number
await http.get('/critical-endpoint', { retryTimes: 3 });axios-extensions augments Axios request types for:
cacheforceUpdatethresholdretryTimes
When importing shared cache contracts in TypeScript, use type-only imports:
import type { ICacheLike } from 'axios-extensions';If your project has strict interop settings, enabling these can improve import ergonomics:
esModuleInterop: trueallowSyntheticDefaultImports: true
Set process.env.LOGGER_LEVEL=info in Node-based development to enable internal info logging.
npm run lint
npm test
npm run buildMIT