s3-file-uploader
A small Node.js wrapper around AWS S3 for uploading, downloading, deleting, and listing files, without writing AWS SDK boilerplate in every project that needs it.
Built on AWS SDK for JavaScript v3 (@aws-sdk/client-s3 and
@aws-sdk/lib-storage). Version 1.x depended on AWS SDK v2, which
reached end-of-support
and printed a warning on every install. Version 2.x removes that dependency
entirely. See Migrating from 1.x below if you are upgrading.
Install
npm install s3-file-uploader
Requires Node.js 20 or later, the minimum supported by the current AWS SDK
v3 release line. Earlier SDK v3 releases support Node 18, but they carry an
unpatched critical fast-xml-parser vulnerability
(GHSA-8gc5-j5rx-235r
and related advisories) that is only fixed in the Node-20-only releases, so
this package does not support Node 18.
Quick start
const S3FileUploader = require('s3-file-uploader');
const uploader = new S3FileUploader({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: 'eu-west-1',
bucketName: 'my-bucket',
});
const location = await uploader.uploadFile('./invoice.pdf', 'invoices/invoice.pdf');
console.log('Uploaded to', location);
If you omit accessKeyId / secretAccessKey (for example, running on an EC2
instance or in Lambda with an attached IAM role), the SDK falls back to its
default credential provider chain
automatically.
Usage examples
Upload with progress
Useful for CLIs and upload dashboards. lib-storage emits httpUploadProgress
after each part completes.
await uploader.uploadFile('./video.mp4', 'videos/video.mp4', {
onProgress: (progress) => {
console.log(`${progress.loaded} / ${progress.total} bytes`);
},
});
Large files (multipart upload)
No extra code needed. Once a file crosses the 5 MB part-size threshold,
uploadFile automatically switches to a multipart upload and uploads parts
in parallel (lib-storage defaults: 5 MB parts, 4 concurrent parts).
// A 500 MB file is uploaded in parallel 5 MB parts automatically.
await uploader.uploadFile('./backup.tar.gz', 'backups/backup.tar.gz');
Presigned URLs
Give a browser or another service temporary, credential-free access to a private object.
// A link a user can download from directly, valid for 10 minutes.
const downloadUrl = await uploader.getDownloadUrl('invoices/invoice.pdf', 600);
// A link a client can upload to directly, bypassing your server entirely.
const uploadUrl = await uploader.getUploadUrl('uploads/avatar.png', 300);
Delete and list
const keys = await uploader.listFiles('invoices/');
// ['invoices/invoice.pdf', 'invoices/invoice-2.pdf']
await uploader.deleteFile('invoices/invoice.pdf');
API
new S3FileUploader(config)
| Field | Type | Required | Description |
|---|---|---|---|
accessKeyId |
string | no | AWS access key. Omit to use the default credential provider chain. |
secretAccessKey |
string | no | AWS secret key. Required if accessKeyId is set. |
region |
string | yes | AWS region the bucket lives in, e.g. 'eu-west-1'. |
bucketName |
string | yes | The S3 bucket every method operates on. |
s3Client |
S3Client |
no | Advanced: inject your own @aws-sdk/client-s3 client instead of building one from the fields above. Mainly for tests. |
uploader.uploadFile(filePath, destinationPath, options?)
Reads filePath from local disk and uploads it to destinationPath in the
bucket. Returns the object's public S3 URL as a string. Automatically uses
multipart upload for large files.
options.onProgress(optional):(progress) => void, called with{ loaded, total, part, Key, Bucket }ashttpUploadProgressfires.
uploader.deleteFile(destinationPath)
Deletes one object. Resolves true once S3 confirms the delete.
uploader.listFiles(prefix?)
Lists object keys in the bucket. Pass a prefix to list only a folder.
Returns an array of key strings (empty array if nothing matches). Note this
returns at most 1000 keys per call (S3's own ListObjectsV2 page size); it
does not paginate through larger buckets.
uploader.getDownloadUrl(destinationPath, expiresInSeconds?)
Returns a presigned GET URL. Default expiry is 3600 seconds (1 hour).
uploader.getUploadUrl(destinationPath, expiresInSeconds?)
Returns a presigned PUT URL. Default expiry is 3600 seconds (1 hour). The
caller uploading through this URL sends the raw file body as the PUT
request body; it does not accept multipart form data.
Limits, honestly
- No retry policy beyond what the AWS SDK does by default. A flaky network connection can still fail an upload; catch and retry in your own code if that matters to you.
listFilesdoes not paginate. A bucket prefix with more than 1000 objects only returns the first page.- No built-in file-type or size validation before upload. Check that yourself if you accept files from untrusted users.
- Credentials passed in
configare used as-is; this package does not store, cache, or send them anywhere except to AWS.
Migrating from 1.x
Version 2.0.0 replaces the aws-sdk (v2) dependency with the modular AWS
SDK v3 (@aws-sdk/client-s3, @aws-sdk/lib-storage,
@aws-sdk/s3-request-presigner). This is a breaking change for anyone
who reached past the public API into SDK internals.
Unchanged, no code changes needed:
new S3FileUploader({ accessKeyId, secretAccessKey, region, bucketName })uploader.uploadFile(filePath, destinationPath)still returns the S3 location URL string.
Changed:
uploader.s3used to be anAWS.S3instance (SDK v2). It is now anS3Clientinstance (SDK v3). Any code that called v2-style methods directly onuploader.s3(e.g.uploader.s3.upload(params).promise()) needs to switch to v3 command syntax (uploader.s3.send(new PutObjectCommand(params))), or better, use the newuploadFile/deleteFile/listFilesmethods instead of reaching intouploader.s3at all.- The
aws-sdkpackage is no longer a dependency. If your own code also importedaws-sdkdirectly (separately from this package), that import keeps working only as long as you keepaws-sdkin your ownpackage.json; consider migrating it too before v2 support ends fully.
New in 2.0.0: deleteFile, listFiles, getDownloadUrl, getUploadUrl,
upload progress via options.onProgress, and automatic multipart upload for
large files.
Testing
The test suite runs entirely offline with Node's built-in test runner. No AWS account, credentials, or network access needed.
npm test
Contributing
See CONTRIBUTING.md.
Security
See SECURITY.md.
License
MIT, see LICENSE.
Author
Tisankan Jeyakumar Email: hello@tisankan.dev Website: https://tisankan.dev GitHub: https://github.com/Tisankan-dev