How to submit a POST request from a form and handle it in API route by NextJS and Express in NodeJS. Text inputs from form Front <form action="/api/action_for_inputs_post" method="POST" autoComplete="off" name="myForm" > <fieldset> <legend>Radios</legend> <input type="radio" id="html" name="fav_language" defaultValue="HTML" defaultChecked /> <label htmlFor="html">HTML</label><br /> <input type="radio" id="css" name="fav_language" defaultValue="CSS" /> <label htmlFor="css">CSS</label><br /> <input type="radio" id="javascript" name="fav_language" defaultValue="JavaScript" /> <label htmlFor="javascript">JavaScript</label> </fieldset> <fieldset> <legend>Checkboxes</legend> <input type="checkbox" id="vehicle1" name="vehicles" defaultValue="Bike" defaultChecked /> <label htmlFor="vehicle1"> I have a bike</label><br /> <input type="checkbox" id="vehicle2" name="vehicles" defaultValue="Car" defaultChecked /> <label htmlFor="vehicle2"> I have a car</label><br /> <input type="checkbox" id="vehicle3" name="vehicles" defaultValue="Boat" /> <label htmlFor="vehicle3"> I have a boat</label> </fieldset> <button>Submit</button> <style jsx global>{` * { box-sizing: border-box; } fieldset { margin-bottom: 20px; padding: 10px; } legend { font-weight: 600; } label { margin: 5px; } `}</style> </form> Route in Next // pages\api\action_for_inputs_post.js export default function handler(req, res) { res.status(200).json(req.body) } Route in Node app.use('/action', express.urlencoded( {extended: true} )) app.post('/action', (req, res) => res.status(200).json(req.body)) Output File upload & save from form Front function FileUpload(props) { return ( <form action="/api/action_for_file_upload" method="POST" autoComplete="off" name="myForm" encType="multipart/form-data"> <fieldset> <legend>Checkboxes</legend> <input type="checkbox" id="vehicle1" name="vehicles" defaultValue="Bike" defaultChecked /> <label htmlFor="vehicle1"> I have a bike</label><br /> <input type="checkbox" id="vehicle2" name="vehicles" defaultValue="Car" defaultChecked /> <label htmlFor="vehicle2"> I have a car</label><br /> <input type="checkbox" id="vehicle3" name="vehicles" defaultValue="Boat" /> <label htmlFor="vehicle3"> I have a boat</label> </fieldset> <fieldset> <legend>File</legend> <label htmlFor="my-file">Select a file:</label> <input type="file" id="myfile1" name="my-file" multiple /> <input type="file" id="myfile2" name="my-file" multiple /> <input type="file" id="myfile3" name="my-file" multiple /> </fieldset> <button>Submit</button> <style jsx global>{` * { box-sizing: border-box; } fieldset { margin-bottom: 20px; padding: 10px; } legend { font-weight: 600; } label { margin: 5px; } `}</style> </form> ) } Route in Next // pages/api/action_for_file_upload.js import multer from "multer" export const config = { api: { bodyParser: false, }, } let storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, 'upload') }, filename: function (req, file, cb) { cb(null, file.originalname) }, }) let upload = multer({ storage: storage }) export default async function handler (req, res) { upload.array("my-file")(req, {}, err => { req.files.forEach(function addMegaBytesProp(el) { return el.sizeInMb = (el.size / 1024 / 1024)?.toFixed(6) + " Mb" }) res.json({ "req.body": req.body, "req.files": req.files }) }) } Route in Node // security app.use(function(req, res, next) { res.header("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;") next() }) // multer // npm i multer const multer = require('multer') const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, 'uploads/') }, filename: function (req, file, cb) { cb(null, file.originalname ) } }) const upload = multer({ storage: storage }) app.use('/action', express.urlencoded({ extended: true })) app.post('/action', upload.array('my-file'), // for <input name="my-file"> (req, res) => { req.files.forEach(function addMegaBytesProp(el) { return el.sizeInMb = (el.size / 1024 / 1024)?.toFixed(6) + " Mb" }) res.json({'req.body': req.body, 'req.file': req?.file, 'req.files': req?.files}) } ) Output File upload & read without saving Front function FileUploadWithoutSaving() { return ( <form action="/api/action_for_consuming_data" method="POST" autoComplete="off" name="myForm" encType="multipart/form-data"> <fieldset> <legend>File</legend> <label htmlFor="my-file">Select a file:</label> <input type="file" id="myfile1" name="my-file"/> </fieldset> <button>Submit</button> <style jsx global>{` * { box-sizing: border-box; } fieldset { margin-bottom: 20px; padding: 10px; } legend { font-weight: 600; } label { margin: 5px; } `}</style> </form> ) } Route in Next // // pages\api\action_for_consuming_data.js import multer from "multer" export const config = { api: { bodyParser: false, }, } const storage = multer.memoryStorage() let upload = multer({ storage }) export default async function handler (req, res) { upload.array("my-file")(req, {}, err => { res.json({ 'req.body': req.body, 'req.files': req.files, 'fileContent': req.files[0].buffer.toString() }) }) } Route in Node // multer const multer = require('multer') const storage = multer.memoryStorage() const upload = multer({ storage }) app.use('/action', express.urlencoded({ extended: true })) app.post('/action', upload.array('my-file'), // for <input name="my-file"> (req, res) => { res.json({ 'req.body': req.body, 'req.files': req.files, 'fileContent': req.files[0].buffer.toString() }) } ) Output JSON from fetch Front function JsonFromFetch() { const [response, setResponse] = useState('not yet') async function sendJsonWithFetch () { const url = '/api/action_to_get_json_from_fetch_request' const options = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ user: { name: "John", email: "john@example.com" } }) } let response = await fetch(url, options) let result = await response.json() setResponse(JSON.stringify(result)) } return ( <div> <button onClick={sendJsonWithFetch}>Send JSON</button> <div>Response: {response}</div> </div> ) } Route in Next // pages\api\action_to_get_json_from_fetch_request.js export default async function handler (req, res) { res.json(req.body) } Route in Node app.use('/action', express.json()) app.post('/action', (req, res) => res.json(req.body)) Text from fetch Front function TextFromFetch() { const [response, setResponse] = useState('not yet') async function sendTextWithFetch () { const url = '/api/action_to_get_text_from_fetch_request' const options = { method: 'POST', body: 'pure text' } let response = await fetch(url, options) let result = await response.text() setResponse(result) } return ( <div> <button onClick={sendTextWithFetch}>Send Text</button> <div>Response: {response}</div> </div> ) } Route in Next // pages\api\action_to_get_text_from_fetch_request.js export default async function handler (req, res) { res.send(req.body) } Route in Node app.use('/action', express.text()) app.post('/action', (req, res) => res.send(req.body)) formData with data & file from fetch Front function FormDataWithFileFromFetch() { const [response, setResponse] = useState('not yet') const input1 = useRef() const input2 = useRef() async function sendFormDataWithFetch (e) { e.preventDefault() const url = '/api/action_to_get_formData_from_fetch_request' const formData = new FormData() formData.append('name', 'John') formData.append('age', 35) formData.append('file1', input1.current.files[0]) formData.append('file2', input2.current.files[0]) const options = { method: 'POST', body: formData } let response = await fetch(url, options) let result = await response.json() setResponse(JSON.stringify(result)) } return ( <> <form action="#" method="POST" autoComplete="off" name="myForm" encType="multipart/form-data"> <fieldset> <legend>File</legend> <label htmlFor="my-file">Select a file:</label> <input ref={input1} type="file" id="myfile1" name="my-file" multiple /> <input ref={input2} type="file" id="myfile2" name="my-file" multiple /> </fieldset> <button onClick={sendFormDataWithFetch}>Submit</button> <style jsx global>{` * { box-sizing: border-box; } fieldset { margin-bottom: 20px; padding: 10px; } legend { font-weight: 600; } label { margin: 5px; } `}</style> </form> <div>Response: {response}</div> </> ) } Route in Next // pages\api\action_to_get_text_from_fetch_request.js import nextConnect from "next-connect" import multer from "multer" export const config = { api: { bodyParser: false } } let storage = multer.diskStorage({ destination: (req, file, cb) => cb(null, 'upload'), filename: (req, file, cb) => cb(null, file.originalname), }) const apiRoute = nextConnect() apiRoute.use(multer({ storage }).any()) apiRoute.post((req, res) => { console.log(req.body) console.log(req.files) res.status(200).json({'req.body': req.body, 'req.files': req.files}) }) export default apiRoute Route in Node const multer = require('multer') const storage = multer.diskStorage({ destination: (req, file, cb) => cb(null, 'uploads'), filename: (req, file, cb) => cb(null, file.originalname), }) const upload = multer({ storage }) app.post('/action', upload.array('file'), (req, res) => { res.send('body :' + JSON.stringify(req.body) + ' ' + 'files :' + JSON.stringify(req.files)) })