Choosing Between Global and Instance-Based Axios Interceptors for Centralized API Handling
Learn how to choose between global and instance‑based Axios interceptors, implement auth headers centrally, and verify the setup with a network inspector.
06 Aug 2026, 17:25 UTC

The Problem: Duplicated Request Logic Across API Calls
In a JavaScript or TypeScript application that calls multiple REST endpoints, developers often repeat the same code to attach authentication tokens, log request metadata, or handle common error statuses. This duplication increases maintenance effort and the risk of inconsistencies.
The useful takeaway is to centralize this logic with Axios interceptors, choosing the right scope to avoid leaking headers to unintended services.
Decision: Global vs Instance-Based Interceptors
| Aspect | Global Interceptors (axios) | Custom Instance Interceptors |
|---|---|---|
| Scope | Every request made via the default axios object | Only requests made via the specific axios.create() instance |
| Isolation | Low – headers added here are sent to all outgoing calls, including third‑party APIs | High – each instance can have its own baseURL and header set |
| Configuration Effort | Single place to set up | Requires creating and exporting an instance, but keeps concerns separate |
| Typical Use Case | Small projects with a single backend | Medium to large apps that talk to multiple APIs or micro‑services |
Trade‑offs
- Global interceptors are quick to implement but can cause accidental header leakage, making debugging harder when a third‑party service receives unexpected Authorization headers.
- Instance‑based interceptors add a small amount of boilerplate (creating the instance) but guarantee that authentication or logging logic only affects the intended API, simplifying testing and reducing side‑effects.
- If you need different interceptor chains for different services (e.g., one that retries on 5xx, another that does not), instance‑based approach lets you maintain separate stacks without worrying about execution order conflicts.
Implementation: Instance‑Based Interceptors
Step 1: Create an Isolated Axios Instance
Create a dedicated client for your backend. This ensures any headers you add are scoped to that client.
import axios from 'axios';
const apiClient = axios.create({
baseURL: 'https://api.example.com/v1',
timeout: 12000,
});
export default apiClient;
Step 2: Attach a Request Interceptor for Authentication
The interceptor must return the config object; otherwise the promise chain breaks and the request is never sent.
apiClient.interceptors.request.use(
(config) => {
const token = localStorage.getItem('access_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config; // required
},
(error) => {
return Promise.reject(error);
}
);
Step 3: Attach a Response Interceptor for Global Error Handling
Here we normalize successful responses (if the API wraps data) and redirect on 401.
apiClient.interceptors.response.use(
(response) => {
// If your API returns { data: {...}, status: 'ok' }, unwrap it
if (response.data && response.data.data !== undefined) {
return response.data.data;
}
return response;
},
(error) => {
if (error.response && error.response.status === 401) {
console.warn('Unauthorized – redirecting to login');
// Example redirect; replace with your router navigation
window.location.href = '/login';
}
return Promise.reject(error);
}
);
Verification and Practical Checks
- Run your application and make a request using
apiClient.get('/users'). - Open the browser’s Developer Tools → Network tab.
- Find the outgoing request and inspect its Request Headers.
- Confirm that the
Authorizationheader contains the expected Bearer token. - To test the response interceptor, mock a 401 response (e.g., with JSON Server or Prism) and verify that the console warning appears and the redirect occurs.
Limitations and Rollback
- Execution order matters: interceptors run in the sequence they were added. If you add multiple request interceptors, ensure dependent logic is ordered correctly.
- Overloading interceptors with complex business logic can obscure failures; keep them focused on cross‑cutting concerns like auth, logging, or basic error mapping.
- If you need to remove an interceptor (for example, during testing), store the ID returned by
.use()and calleject(id).
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.