Centralizing HTTP Logic with Axios Interceptors: A Practical Guide
Axios interceptors let you centralize auth, logging, and error handling in one place. Learn how to set up a shared instance, register interceptors in the right order, and avoid common pitfalls with this practical guide.
09 Jul 2026, 04:34 UTC

Problem: Scattered Request Logic
When building a single‑page app or a microservice, you often find dozens of axios.get, axios.post calls sprinkled across components and services. Each of those calls may need the same auth header, a retry policy, or custom logging. Duplicating that logic everywhere leads to maintenance headaches and subtle bugs.
Thesis: Interceptors Turn Axios into a Middleware Pipeline
Axios interceptors give you a global hook that runs for every request or response. By registering a handful of interceptors on a single axios instance, you can centralize cross‑cutting concerns, keep your request code clean, and guarantee consistent behavior.
Setting Up a Shared Axios Instance
Instead of importing the default axios everywhere, create a dedicated instance:
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
});
export default api;
All subsequent calls will use this instance, so any interceptor you attach will apply globally.
Registering Interceptors
Interceptors are added in the order they should run. The first interceptor you register is the outermost wrapper; the last one is the innermost. When a request is sent, the stack unwinds from last to first.
- Request interceptors (modify config)
- Response interceptors (transform data)
- Error interceptors (unified handling)
Example: Auth Header + Logging
Below is a concrete example that shows how to add an Authorization header and log every outgoing request. The logging interceptor is registered after the auth one so it sees the final config.
// api.js
import api from './api';
// 1. Auth interceptor – runs first
api.interceptors.request.use((config) => {
const token = localStorage.getItem('jwt'); // replace with real source
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
});
// 2. Logging interceptor – runs second
api.interceptors.request.use((config) => {
console.log('Request:', config.method.toUpperCase(), config.url, config.headers);
return config;
});
// 3. Response interceptor – transform data
api.interceptors.response.use((response) => {
// Assume API wraps data in { payload: ... }
return response.data.payload;
});
// 4. Error interceptor – unified handling
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response && error.response.status === 401) {
// e.g., redirect to login
}
return Promise.reject(error);
}
);
Now any component can simply do:
import api from './api';
api.get('/users')
.then((users) => console.log(users))
.catch((err) => console.error(err));
Both the auth header and the log statement will appear automatically.
Order Matters: A Visual Flow
| Step | Description |
|---|---|
| 1 | Auth interceptor adds header |
| 2 | Logging interceptor sees header |
| 3 | Request sent to network |
| 4 | Response interceptor transforms payload |
| 5 | Error interceptor handles 401 |
Trade‑Offs & Limitations
- Global Scope – All requests share the same interceptors. If you need per‑request customization, pass
configoverrides or create a separateaxiosinstance. - Ordering Pitfalls – Adding a header after a signing step can break the signature. Always register interceptors in a logical order and document it.
- Side‑Effects – Interceptors that mutate shared state (e.g., a global Redux store) can cause race conditions when many concurrent requests run.
- Cleanup – In a component‑heavy app, don’t register interceptors inside component mount hooks unless you also remove them on unmount. Otherwise you’ll accumulate duplicate interceptors.
Actionable Takeaways
- Create a dedicated
apiinstance and export it. - Register interceptors in a top‑down order that reflects the logical pipeline.
- Test the stack: register a dummy header interceptor and a logging interceptor, then assert the header appears in the network tab.
- Document the interceptor order in your README or code comments.
- Remember to clean up interceptors if you ever create them in component lifecycles.
By treating Axios as a middleware pipeline, you turn scattered request logic into a single, maintainable source of truth. This not only speeds up development but also reduces bugs and makes future refactors trivial.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.