How to Use an Axios POST Request to Send Form Data to an Express Server

Use URLSearchParams for simple key-value pairs or FormData for multipart uploads, ensuring your Express server uses express.urlencoded() middleware to parse the payload into req.body.

Sending form data from a client to a server is a fundamental pattern in web development. When using an axios POST request to send form data to an Express.js backend, you must align the client-side encoding with the server-side parsing middleware. This guide references the actual implementation in the expressjs/express repository to show you the proper configuration.

Understanding Form Data Encoding Types

Before writing code, you need to choose the correct payload format. The two primary standards for HTML form submission are application/x-www-form-urlencoded for simple key-value pairs and multipart/form-data for binary data like files. Your choice determines which Axios API to use and which Express middleware must be active.

Sending Simple Form Data with URLSearchParams

For standard text fields, the URLSearchParams interface provides a clean, native way to construct an application/x-www-form-urlencoded payload. Axios automatically detects this object and sets the Content-Type: application/x-www-form-urlencoded header for you.

import axios from 'axios';

const params = new URLSearchParams();
params.append('username', 'bob');
params.append('email', 'bob@example.com');

axios.post('http://localhost:3000/login', params)
  .then(res => console.log(res.data))
  .catch(err => console.error(err));

Express Server Configuration

On the server side, the express.urlencoded() middleware parses this payload. According to the source code in lib/express.js, this middleware is a thin wrapper around the body-parser library's urlencoded parser. The test suite in test/express.urlencoded.js validates that the middleware correctly populates req.body with the submitted fields.

import express from 'express';
const app = express();

// Enable parsing of urlencoded bodies
// Source: lib/express.js
app.use(express.urlencoded({ extended: true }));

app.post('/login', (req, res) => {
  // req.body contains { username: 'bob', email: 'bob@example.com' }
  console.log(req.body);
  res.send('Received');
});

app.listen(3000);

The extended: true option instructs the underlying qs library to support rich objects and arrays, while extended: false uses the simpler querystring library.

Handling Multipart Form Data and File Uploads

When you need to transmit files or binary data, you must use multipart/form-data encoding. In this scenario, URLSearchParams is insufficient; you need the FormData API. Unlike URLSearchParams, Axios does not automatically set the Content-Type header for FormData because the boundary string must be calculated by the browser or the form-data polyfill.

import axios from 'axios';

const form = new FormData();
form.append('title', 'My Photo');
form.append('photo', fileInput.files[0]); // Browser File object

axios.post('http://localhost:3000/upload', form, {
  headers: { 'Content-Type': 'multipart/form-data' }
})
  .then(res => console.log(res.data))
  .catch(err => console.error(err));

Note that express.urlencoded() does not parse multipart/form-data. For this content type, you need a dedicated parser such as multer or formidable. The example below uses multer to handle the file stream and text fields:

import express from 'express';
import multer from 'multer';
const upload = multer();
const app = express();

app.post('/upload', upload.single('photo'), (req, res) => {
  // req.body contains text fields
  console.log(req.body.title);
  // req.file contains the binary data
  console.log(req.file.originalname);
  res.send('File received');
});

app.listen(3000);

Alternative: Manual Query String Encoding

For environments where you need explicit control over serialization options—such as defining array formats or delimiter characters—you can use the qs library to manually construct the payload string before sending your axios POST request to send form data.

import axios from 'axios';
import qs from 'qs';

const data = qs.stringify({ 
  username: 'bob', 
  tags: ['admin', 'editor']
});

axios.post('http://localhost:3000/login', data, {
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
  .then(res => console.log(res.data))
  .catch(err => console.error(err));

This approach bypasses URLSearchParams and allows you to specify encoding parameters that match your server's expectations.

Summary

  • Use URLSearchParams for simple application/x-www-form-urlencoded payloads; Axios automatically sets the correct Content-Type header.
  • Use FormData for multipart/form-data when transmitting files or binary data; you must manually set the Content-Type header or let the browser set it with the proper boundary.
  • Configure your Express server with express.urlencoded() (exported from lib/express.js) to parse urlencoded bodies into req.body.
  • For multipart uploads, use multer or similar middleware instead of express.urlencoded().
  • For advanced serialization control, use the qs library to manually stringify objects before sending.

Frequently Asked Questions

Does Axios automatically set Content-Type for form data?

Axios automatically sets Content-Type: application/x-www-form-urlencoded when you pass a URLSearchParams object as the request body. However, when using FormData for multipart uploads, you must explicitly set the Content-Type: multipart/form-data header or allow the browser to set it automatically with the correct boundary string.

What is the difference between URLSearchParams and FormData?

URLSearchParams creates an application/x-www-form-urlencoded payload suitable for simple key-value pairs of text data. FormData constructs a multipart/form-data payload that supports binary files, streams, and complex field structures. Choose URLSearchParams for login forms and search queries; use FormData for image uploads and file transfers.

Why is my Express req.body empty when receiving form data?

An empty req.body typically indicates that the express.urlencoded() middleware is not active, or that the client sent multipart/form-data without the server using a compatible parser like multer. Ensure you have called app.use(express.urlencoded({ extended: true })) before your route handlers, and verify that the Content-Type header in the request matches the parser configuration as tested in test/express.urlencoded.js.

Can I send files using URLSearchParams instead of FormData?

No, URLSearchParams only supports string values and cannot encode binary file data. To upload files to an Express server, you must use FormData on the client side and a multipart parser such as multer on the server side. Attempting to append a File object to URLSearchParams will result in the string "[object File]" being transmitted instead of the actual file content.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →