multipart-form-data format
axios can send requests in the multipart/form-data format. This format is commonly used when uploading files. To send a request in this format, you need to create a FormData object and append the data to it. Then you can pass the FormData object to the data property of the axios request config.
const formData = new FormData();
formData.append('foo', 'bar');
axios.post('https://httpbin.org/post', formData);In node.js, you can use the form-data library as follows:
const FormData = require('form-data');
const form = new FormData();
form.append('my_field', 'my value');
form.append('my_buffer', Buffer.alloc(10));
form.append('my_file', fs.createReadStream('/foo/bar.jpg'));
axios.post('https://example.com', form);Automatic serialization to FormData New
Starting from v0.27.0, Axios supports automatic object serialization to a FormData object if the request Content-Type header is set to multipart/form-data. This means that you can pass a JavaScript object directly to the data property of the axios request config. For example when passing data to a POST request:
import axios from 'axios';
axios
.post(
'https://httpbin.org/post',
{ x: 1 },
{
headers: {
'Content-Type': 'multipart/form-data',
},
}
)
.then(({ data }) => console.log(data));In the node.js build, the (form-data) polyfill is used by default. You can overload the FormData class by setting the env.FormData config variable, but you probably won't need it in most cases:
const axios = require('axios');
var FormData = require('form-data');
axios
.post(
'https://httpbin.org/post',
{ x: 1, buf: Buffer.alloc(10) },
{
headers: {
'Content-Type': 'multipart/form-data',
},
}
)
.then(({ data }) => console.log(data));Header policy for Node.js FormData Node.js only
When you pass a Node.js FormData object that exposes getHeaders() (such as the form-data package), axios copies all headers it returns onto the request by default. This preserves v1 compatibility but can be problematic when the FormData object comes from an untrusted source — getHeaders() could overwrite headers like Authorization or inject arbitrary ones.
Set formDataHeaderPolicy: 'content-only' to copy only Content-Type and Content-Length from getHeaders(), then set any other headers explicitly via the request headers config:
await axios.post("https://example.com/upload", form, {
formDataHeaderPolicy: "content-only",
headers: {
Authorization: "Bearer my-token",
},
});The default value is 'legacy'. See formDataHeaderPolicy in the request config reference for details.
Supported endings
Axios FormData serializer supports some special endings to perform the following operations:
{}- serialize the value with JSON.stringify[]- unwrap the array-like object as separate fields with the same key
WARNING
Note: unwrap/expand operation will be used by default on arrays and FileList objects
Configuring the FormData serializer
FormData serializer supports additional options via config.formSerializer: object property to handle rare cases:
visitor: Function- user-defined visitor function that will be called recursively to serialize the data object to a FormData object by following custom rules.dots: boolean = false- use dot notation instead of brackets to serialize arrays and objects;metaTokens: boolean = true- add the special ending (e.guser{}: '{"name": "John"}') in the FormData key. The back-end body-parser could potentially use this meta-information to automatically parse the value as JSON.indexes: null|false|true = false- controls how indexes will be added to unwrapped keys of flat array-like objectsnull- don't add brackets (arr: 1,arr: 2,arr: 3)false(default) - add empty brackets (arr[]: 1,arr[]: 2,arr[]: 3)true- add brackets with indexes (arr[0]: 1,arr[1]: 2,arr[2]: 3)
maxDepth: number = 100- maximum object nesting depth the serializer will recurse into. If the input exceeds this depth, anAxiosErrorwithcode: 'ERR_FORM_DATA_DEPTH_EXCEEDED'is thrown. This protects server-side applications from DoS attacks via deeply nested payloads. Set toInfinityto disable the limit.
// Allow deeper nesting for schemas that legitimately exceed 100 levels:
axios.postForm('/api', data, { formSerializer: { maxDepth: 200 } });Security note
The default limit of 100 is intentional. Server-side code that forwards client-controlled JSON to axios as data is vulnerable to a call-stack overflow without this guard. Only raise maxDepth if your schema genuinely requires it.
For example, if we have an object like this:
const obj = {
x: 1,
arr: [1, 2, 3],
arr2: [1, [2], 3],
users: [
{ name: 'Peter', surname: 'Griffin' },
{ name: 'Thomas', surname: 'Anderson' },
],
'obj2{}': [{ x: 1 }],
};The following steps will be executed by the Axios serializer internally:
const formData = new FormData();
formData.append('x', '1');
formData.append('arr[]', '1');
formData.append('arr[]', '2');
formData.append('arr[]', '3');
formData.append('arr2[0]', '1');
formData.append('arr2[1][0]', '2');
formData.append('arr2[2]', '3');
formData.append('users[0][name]', 'Peter');
formData.append('users[0][surname]', 'Griffin');
formData.append('users[1][name]', 'Thomas');
formData.append('users[1][surname]', 'Anderson');
formData.append('obj2{}', '[{"x":1}]');Axios supports the following shortcut methods: postForm, putForm, patchForm which are just the corresponding http methods with the Content-Type header preset to multipart/form-data.