Axios Config: Shallow vs Deep Merging Explained
When making HTTP requests with Axios, configurations can be defined at the global level, on a specific Axios instance, or individually within a single request. Understanding the difference between shallow and deep merging of these configurations is essential for effectively managing headers, query parameters, and other request options without accidentally wiping out critical default settings. This article breaks down how shallow and deep merging work in Axios, which properties are affected by each approach, and how to properly structure your request configurations.
Shallow Merging
Shallow merging (often achieved using Object.assign() or
the object spread operator ...) copies top-level properties
from one object to another. If a property value is a primitive (such as
a string, number, or boolean), the value is overwritten. If a property
value is a nested object, the shallow merge completely replaces the
entire target object reference with the source object reference instead
of combining their inner properties.
Example in Axios Context
If Axios used pure shallow merging for all properties, a scenario with query parameters would behave like this:
// Instance configuration
const api = axios.create({
params: {
apiKey: '12345',
version: 'v1'
}
});
// Request configuration
api.get('/users', {
params: {
limit: 10
}
});Under a shallow merge, the request's params object
({ limit: 10 }) completely replaces the instance
params object. As a result, apiKey and
version are discarded, and only limit=10 is
sent to the server.
Deep Merging
Deep merging (recursive merging) inspects nested objects. When both the source and target contain an object at the same key, deep merging enters those objects and merges their sub-properties rather than replacing the parent object entirely.
Example in Axios Context
Using the previous example under a deep merge strategy, the resulting
params object would be:
{
apiKey: '12345',
version: 'v1',
limit: 10
}Both the default configuration properties and the request-level properties are preserved.
How Axios Handles Merging
Axios does not apply a single blanket merge strategy across all configuration properties. Instead, it uses a hybrid approach based on the property type:
1. Headers (Deep Merged)
The headers configuration receives specialized deep
merging. Axios combines headers from multiple layers according to a
strict hierarchy:
axios.defaults.headers.commonaxios.defaults.headers[method](e.g.,get,post)- Instance-level headers
- Request-level headers
If you define an Authorization header at the instance
level and a Content-Type header at the request level, Axios
deep-merges them so both headers are sent in the final HTTP request.
2. General Configuration Properties (Shallowly Replaced)
Most non-header properties use shallow replacement. These include:
params(URL query parameters)data(request body)auth(Basic authentication credentials)timeout,baseURL,responseType,validateStatus
For these properties, whatever you specify at the request level completely replaces the default or instance-level setting.
3. Arrays (Replaced, Not Merged)
Properties that hold arrays, such as transformRequest
and transformResponse, are completely overwritten by
lower-level configurations rather than concatenated.
Summary of Differences
| Feature | Shallow Merging | Deep Merging |
|---|---|---|
| Object Handling | Replaces nested objects entirely | Merges sub-properties inside nested objects |
| Axios Usage | Applied to params,
auth, data, arrays, and primitives |
Applied specifically to
headers |
| Risk | Can unintentionally drop baseline nested properties | Can unintentionally retain stale sub-properties |
| Precedence | Later top-level values overwrite earlier top-level values | Deeper values overwrite earlier values at the same key path |
To avoid unexpected request behavior, always supply complete nested
objects (such as params) when overriding them at the
request level, while relying on Axios to automatically preserve and
merge your baseline headers.