Axios Instance and Configuration — Complete Guide
In this tutorial, you'll learn about Axios instance configuration. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Axios instances are custom configurations that let you create pre-configured HTTP clients with default settings, reducing repetitive code across your application's API calls.
What You'll Learn
By the end of this tutorial, you'll create custom Axios instances, set default configurations, merge per-request configs, organize API modules, and share instances across components.
Why It Matters
Without instances, every API call repeats the same base URL, headers, and timeout settings. Instances centralize configuration: change the base URL in one place and every request updates. This is essential for scaling applications.
Real-World Use
Durga Antivirus Pro creates separate Axios instances for different services: one for the threat database API (base URL, 5s timeout, auth headers) and another for the update server (longer timeout, progress tracking). Each instance has its own interceptors and defaults.
Where This Fits in Your Learning Path
flowchart LR
A["Getting Started"] --> B["**Instance & Config**"]
B --> C["Request Configuration"]
C --> D["Response Schema"]
D --> E["Axios Advanced"]
style B fill:#f97316,stroke:#c2410c,color:#fff
style A fill:#e5e7eb,stroke:#9ca3af,color:#374151
style E fill:#22c55e,stroke:#16a34a,color:#fff
Creating an Instance
Use axios.create() to create a new instance with default configuration.
import axios from 'axios'
const api = axios.create({
baseURL: 'https://api.example.com/v1',
timeout: 5000,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
// Now use `api` like you would use `axios`
const response = await api.get('/users')
Expected output: Requests from the api instance default to https://api.example.com/v1/users with a 5-second timeout and JSON content type headers.
Setting Defaults on Default Axios
You can also set global defaults that apply to all requests from the standard axios object.
axios.defaults.baseURL = 'https://api.example.com'
axios.defaults.headers.common['Authorization'] = 'Bearer token123'
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
axios.defaults.timeout = 10000
Expected output: Every axios request now includes the base URL, auth header, and 10-second timeout by default.
Merging Config Per-Request
Instance defaults merge with per-request configuration. Per-request values override instance defaults.
const api = axios.create({ baseURL: 'https://api.example.com' })
// Override timeout for a specific slow endpoint
const response = await api.get('/reports/detailed', {
timeout: 30000,
headers: {
'X-Request-Priority': 'high'
}
})
console.log(response.data)
Expected output: The request uses the instance's baseURL but overrides the timeout to 30 seconds. The additional X-Request-Priority header is merged with instance defaults.
Organizing API Modules
Create separate instances for different API domains, each with its own base config.
// api/users.js
export const usersApi = axios.create({
baseURL: 'https://api.example.com/users',
timeout: 3000
})
// api/products.js
export const productsApi = axios.create({
baseURL: 'https://api.example.com/products',
timeout: 5000
})
// Import and use in components
import { usersApi } from './api/users'
const users = await usersApi.get('/')
const user = await usersApi.get('/123')
Expected output: Each API module has its own base URL and timeout. The / maps to the full base URL, /123 maps to https://api.example.com/users/123.
Instance Interceptors
Attach interceptors to specific instances for targeted request/response processing.
const api = axios.create({ baseURL: 'https://api.example.com' })
// Request interceptor specific to this instance
api.interceptors.request.use(config => {
config.headers['X-Request-ID'] = crypto.randomUUID()
return config
})
// Response interceptor specific to this instance
api.interceptors.response.use(
response => response.data,
error => {
console.error('API Error:', error.config.url, error.message)
return Promise.reject(error)
}
)
const data = await api.get('/users') // returns response.data directly
Expected output: Every request from this instance gets a unique request ID header. Response interceptor unwraps .data automatically and logs errors.
Common Mistakes
1. Using the default axios for everything
Without instances, changing the base URL requires updating every API call. Use instances to centralize configuration.
2. Forgetting that instance defaults merge, not replace
Per-request config objects merge with instance defaults. Setting headers in a request adds to instance headers rather than replacing them.
3. Creating a new instance for every component
Create instances once and export them as singletons from modules. Creating instances in every component is wasteful and breaks centralization.
4. Not handling instance-specific errors
Interceptors attached to an instance only handle requests from that instance. Global interceptors handle all requests.
5. Mixing axios.defaults with instance defaults
axios.defaults affects the global axios object. Instance defaults only affect that instance. They do not interfere with each other.
Practice Questions
How do you create a custom Axios instance? Use axios.create({ baseURL: '...', timeout: 5000, headers: {} }).
What happens when you set both axios.defaults and instance defaults? They are separate. The global defaults apply to the main axios object. Instance defaults apply only to that instance.
Can instances have their own interceptors? Yes. Each instance can have independent request and response interceptors.
How does per-request config merge with instance defaults? Per-request config is merged on top of instance defaults. Properties like headers are deep-merged.
Why use multiple instances? Each instance represents a different API service with its own base URL, timeout, auth, and interceptor requirements.
Challenge
Create three Axios instances: one for authentication endpoints (auth token management), one for data CRUD (main API), and one for file uploads (long timeout, progress tracking). Each should have appropriate defaults and interceptors.
FAQ
Mini Project
Build an API client module that creates three pre-configured instances for a typical application: authApi (refresh tokens, short timeout), mainApi (CRUD operations, standard config), and uploadApi (no timeout, multipart headers, progress callbacks).
// api/client.js
import axios from 'axios'
export const authApi = axios.create({
baseURL: 'https://api.example.com/auth',
timeout: 3000,
headers: { 'Content-Type': 'application/json' }
})
authApi.interceptors.response.use(
response => response.data,
async error => {
if (error.response?.status === 401) {
// Attempt token refresh logic here
console.log('Token expired, redirect to login')
}
return Promise.reject(error)
}
)
export const mainApi = axios.create({
baseURL: 'https://api.example.com/v2',
timeout: 5000,
headers: { 'Content-Type': 'application/json' }
})
mainApi.interceptors.request.use(config => {
const token = localStorage.getItem('accessToken')
if (token) config.headers.Authorization = `Bearer ${token}`
return config
})
export const uploadApi = axios.create({
baseURL: 'https://api.example.com/uploads',
timeout: 0, // no timeout for uploads
headers: { 'Content-Type': 'multipart/form-data' }
})
What's Next
Dive deeper into request configuration:
| Tutorial | What You'll Learn |
|---|---|
| Request Configuration | Full request config options, params, and customization |
| Response Schema | Understanding the full response object structure |
Related topics: JavaScript module patterns, REST API design principles.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro