AWS S3 Bucket Uploads with JavaScript and TypeScript
Short scripts & snippets for uploading to an AWS S3 Bucket with JavaScript or TypeScript

This article includes short snippets and guides on uploading files with JavaScript & TypeScript for your web apps or scripts.
Any code blocks or code sandboxes will be included in their respective sections or at the end of the article.
Pre-requisites
This guide will not be going over how to create an S3 Bucket or how to create and generate an AWS Access Key. Please refer to external guides.
- An AWS Account
- An S3 Bucket created
- An IAM user with S3 Access and generated access keys
Alternatives
Some other ways you could upload files to S3 without using JS/TS S3 SDK:
- Create a pre-signed URL, that your frontend can directly use to upload files to S3, cutting out the processing on your API side
- Using AWS CLI V2 for simple local upload using your terminal
- Simply uploading via the AWS S3 console
Uploading with JavaScript
Install required packages with your choice of package manager, we’re using pnpm for this article.
pnpm add @aws-sdk/client-s3
Prepare your environment variables, you should use a proper env handler.
// Import your env using dotenv for example
const env = {
BUCKET_NAME: "YOUR_BUCKET_NAME",
AWS_ACCESS_KEY_ID: "XXXXXXXXXXXX",
AWS_SECRET_ACCESS_KEY: "XXXXXXXXXXXXXXXXX",
};Start writing your upload script boilerplate:
const { PutObjectCommand, S3Client } = require("@aws-sdk/client-s3");
const fs = require("fs/promises");
// These are real values examples
const env = {
BUCKET_NAME: "chicken-nuggets-bucket",
AWS_ACCESS_KEY_ID: "AKIAZ6COO6JQLFFDDWDN",
AWS_SECRET_ACCESS_KEY: "MCF8adNBNZWA6OurU5EUL95mx8OqZl5r8PX+aZhy",
};
// Create a new reusable S3 Client
const client = new S3Client({
credentials: {
accessKeyId: env.AWS_ACCESS_KEY_ID,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
},
});
// Our main function to be run
const main = async () => {
...
};
main().catch((err) => console.error(err))Uploading text file
// Extracted into a function
const uploadTextAsFile = async (key, body) => {
const command = new PutObjectCommand({
Bucket: env.BUCKET_NAME,
Key: `${key}.txt`,
Body: body,
});
await client.send(command);
};
// Usage
const main = async () => {
await uploadTextAsFile("hello", "World!");
};Uploading local file or image
// Take note of the extra import here, no need to install it
const fs = require("fs/promises");
// Extracted into a function
const uploadFile = async (fileName) => {
// Try and have a dedicated folder just for files to be uploaded
const selectedFile = await fs.readFile("./uploads/" + fileName)
const command = new PutObjectCommand({
Bucket: env.BUCKET_NAME,
Key: fileName,
Body: selectedFile,
});
await client.send(command);
};
// File upload
const main = async () => {
await uploadFile("my-file.json");
await uploadFile("my-image.png");
};You can extend the upload file function to check if the file exists before uploading or that the file name provided includes a file extension.
Full script can be run just by node upload.js
// # upload.js
const { PutObjectCommand, S3Client } = require("@aws-sdk/client-s3");
const fs = require("fs/promises");
// These are real values examples
const env = {
BUCKET_NAME: "chicken-nuggets-bucket",
AWS_ACCESS_KEY_ID: "AKIAZ6COO6JQLFFDDWDN",
AWS_SECRET_ACCESS_KEY: "MCF8adNBNZWA6OurU5EUL95mx8OqZl5r8PX+aZhy",
};
const client = new S3Client({
credentials: {
accessKeyId: env.AWS_ACCESS_KEY_ID,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
},
});
const uploadTextAsFile = async (key, body) => {
const command = new PutObjectCommand({
Bucket: env.BUCKET_NAME,
Key: `${key}.txt`,
Body: body,
});
await client.send(command);
};
const uploadFile = async (fileName) => {
// Try and have a dedicated folder just for files to be uploaded
const selectedFile = await fs.readFile("./uploads/" + fileName)
const command = new PutObjectCommand({
Bucket: env.BUCKET_NAME,
Key: fileName,
Body: selectedFile,
});
await client.send(command);
};
const main = async () => {
await uploadTextAsFile("hello", "World!");
await uploadFile("my-file.json");
await uploadFile("my-image.png");
};
main().catch((err) => console.error(err))Uploading with TypeScript
For TypeScript, we will need to install extra packages to get things going
pnpm add -D tsx typescript
// # upload.ts
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import fs from "fs/promises";
// These are real values examples
const env = {
BUCKET_NAME: "chicken-nuggets-bucket",
AWS_ACCESS_KEY_ID: "AKIAZ6COO6JQLFFDDWDN",
AWS_SECRET_ACCESS_KEY: "MCF8adNBNZWA6OurU5EUL95mx8OqZl5r8PX+aZhy",
} as const;
const client = new S3Client({
credentials: {
accessKeyId: env.AWS_ACCESS_KEY_ID,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
},
});
const uploadTextAsFile = async (key: string, body: string) => {
const command = new PutObjectCommand({
Bucket: env.BUCKET_NAME,
Key: `${key}.txt`,
Body: body,
});
await client.send(command);
};
const uploadFile = async (fileName: string) => {
// Try and have a dedicated folder just for files to be uploaded
const selectedFile = await fs.readFile("./uploads/" + fileName);
const command = new PutObjectCommand({
Bucket: env.BUCKET_NAME,
Key: fileName,
Body: selectedFile,
});
await client.send(command);
};
const main = async () => {
await uploadTextAsFile("hello", "World!");
await uploadFile("my-file.json");
await uploadFile("my-image.png");
};
main().catch((err) => console.error(err));There is not much difference between the JS and TS versions for this case, but to get the script started simply run pnpm tsx upload.ts
Use as a Backend Service
The above use cases may be better for local scripts you may use yourself, now you may want it as part of an API for your latest side project or successful business site that you are running.
Here is a quick guide that uses Express:
pnpm add express busboy @aws-sdk/client-s3
pnpm add -D typescript tsx @types/node @types/express @types/busboy
// # api.ts
import express, { type Request, type Response } from "express";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import busboy, { FileInfo } from "busboy";
type RawFile = {
fileName: string;
info: FileInfo;
data: Buffer;
};
// You should be using something like dotenv instead
const env = {
PORT: 3000,
BUCKET_NAME: "chicken-nuggets-bucket",
AWS_ACCESS_KEY_ID: "AKIAZ6COO6JQLFFDDWDN",
AWS_SECRET_ACCESS_KEY: "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",
} as const;
const app = express();
const port = env.PORT || 3000;
const client = new S3Client({
credentials: {
accessKeyId: env.AWS_ACCESS_KEY_ID,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
},
});
app.post("/upload", async (req: Request, res: Response) => {
const files = await parseMultipartReq(req);
for (const file of files) {
await uploadFile(file.info.filename ?? file.fileName, file.data);
}
res.status(200).json({ message: "Files uploaded!" });
});
app.listen(port, () => {
console.log(`[server]: Server is running at http://localhost:${port}`);
});
// Parses a request and returns the files
const parseMultipartReq = async (req: Request) => {
const bb = busboy({ headers: req.headers });
// Pipe request stream into busboy
req.pipe(bb);
return new Promise<RawFile[]>((resolve) => {
const files: RawFile[] = [];
// Does a loop throught the files submitted
bb.on("file", (name, stream, info) => {
const fileChunks: Buffer[] = [];
stream.on("data", (chunk) => fileChunks.push(chunk));
stream.on("end", () =>
files.push({ fileName: name, data: Buffer.concat(fileChunks), info })
);
});
bb.on("close", () => resolve(files));
});
};
const uploadFile = async (fileName: string, fileBuffer: Buffer) => {
const command = new PutObjectCommand({
Bucket: env.BUCKET_NAME,
Key: fileName,
Body: fileBuffer,
});
await client.send(command);
};As for running the API, just run pnpm tsx api.ts once running, you can then make a POST request to the http://localhost:5000 with form data.
Any Access Keys you see in the article will no longer be usable by the time the article has been published, you should be using your Access Keys anyway.
Feel free to leave a comment if you require any assistance or if you’re having trouble with external links.






