The AWS SDK for JavaScript v3 targets Node.js, but it runs on the newer JavaScript runtimes too. Bun aims for Node compatibility and installs npm packages directly. Deno reaches npm through npm: specifiers. In both, the same @aws-sdk/client-* packages work.
The differences are not in the SDK API - they are in how each runtime resolves packages and, more importantly, how it grants access to the environment variables and files the credential chain needs. This page shows the working setup for each and the permission gotchas that trip people up.
Import with the npm: prefix: import { S3Client } from "npm:@aws-sdk/client-s3". Deno resolves and caches the npm package.
Deno is secure by default, so you must grant permissions: --allow-net for the HTTPS calls, --allow-env so the credential chain can read AWS_* variables, and --allow-read if it reads ~/.aws config.
You can pin the version in the specifier (npm:@aws-sdk/client-s3@3.x) or manage it in a deno.json imports map.
Node built-ins the SDK uses are available through Deno's Node compatibility layer, but test anything filesystem or stream heavy.
The credential chain needs to read env vars and possibly ~/.aws files. In Deno that means granting --allow-env and --allow-read; in Bun it is generally unrestricted.
Passing an explicit provider such as fromEnv() or fromIni() makes the source unambiguous and avoids relying on runtime-specific defaults.
On a cloud platform, prefer injected environment credentials or the platform's role integration over reading local files.
If a call mysteriously reports missing credentials on Deno, a missing --allow-env is the usual cause.
Deno "PermissionDenied" on env - the credential chain cannot read AWS_* without permission. Fix: run with --allow-env (and --allow-read for shared config).
Missing --allow-net - the HTTPS call is blocked. Fix: grant --allow-net, optionally scoped to the AWS endpoints.
Assuming full Node parity - a rarely used Node API may be missing on either runtime. Fix: test the actual operations you use on the target runtime.
Unpinned versions - a runtime or SDK auto-update changes behavior. Fix: pin both versions and upgrade deliberately.
Reaching for IMDS locally - the default chain may probe instance metadata and stall off-cloud. Fix: pass fromEnv/fromIni explicitly during local development.
Forgetting Deno's npm: prefix - a bare @aws-sdk/client-s3 import fails in Deno without an imports map. Fix: use the npm: specifier or configure deno.json.