skills/bun-guides-http-file-uploads/SKILL.md
Upload files via HTTP using FormData
npx skillsauth add jarle/bun-skills Bun Upload files via HTTP using FormDataInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
To upload files via HTTP with Bun, use the FormData API. Let's start with a HTTP server that serves a simple HTML web form.
const server = Bun.serve({
port: 4000,
async fetch(req) {
const url = new URL(req.url);
// return index.html for root path
if (url.pathname === "/")
return new Response(Bun.file("index.html"), {
headers: {
"Content-Type": "text/html",
},
});
return new Response("Not Found", { status: 404 });
},
});
console.log(`Listening on http://localhost:${server.port}`);
We can define our HTML form in another file, index.html.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Form</title>
</head>
<body>
<form action="/action" method="post" enctype="multipart/form-data">
<input type="text" name="name" placeholder="Name" />
<input type="file" name="profilePicture" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
At this point, we can run the server and visit localhost:4000 to see our form.
bun run index.ts
Listening on http://localhost:4000
Our form will send a POST request to the /action endpoint with the form data. Let's handle that request in our server.
First we use the .formData() method on the incoming Request to asynchronously parse its contents to a FormData instance. Then we can use the .get() method to extract the value of the name and profilePicture fields. Here name corresponds to a string and profilePicture is a Blob.
Finally, we write the Blob to disk using Bun.write().
const server = Bun.serve({
port: 4000,
async fetch(req) {
const url = new URL(req.url);
// return index.html for root path
if (url.pathname === "/")
return new Response(Bun.file("index.html"), {
headers: {
"Content-Type": "text/html",
},
});
// parse formdata at /action // [!code ++]
if (url.pathname === "/action") { // [!code ++]
const formdata = await req.formData(); // [!code ++]
const name = formdata.get("name"); // [!code ++]
const profilePicture = formdata.get("profilePicture"); // [!code ++]
if (!profilePicture) throw new Error("Must upload a profile picture."); // [!code ++]
// write profilePicture to disk // [!code ++]
await Bun.write("profilePicture.png", profilePicture); // [!code ++]
return new Response("Success"); // [!code ++]
} // [!code ++]
return new Response("Not Found", { status: 404 });
},
});
development
Using TypeScript with Bun, including type definitions and compiler options
development
Learn how to write tests using Bun's Jest-compatible API with support for async tests, timeouts, and various test modifiers
testing
Learn how to use snapshot testing in Bun to save and compare output between test runs
testing
Learn about Bun test's runtime integration, environment variables, timeouts, and error handling