bun-types 1.3.2-canary.20251106T140813 → 1.3.2-canary.20251108T140624

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. package/bun.d.ts +102 -6
  2. package/docs/bundler/bytecode.mdx +465 -0
  3. package/docs/bundler/css.mdx +1024 -0
  4. package/docs/bundler/esbuild.mdx +253 -0
  5. package/docs/bundler/executables.mdx +535 -0
  6. package/docs/bundler/fullstack.mdx +1064 -0
  7. package/docs/bundler/hot-reloading.mdx +229 -0
  8. package/docs/bundler/html-static.mdx +386 -0
  9. package/docs/bundler/index.mdx +1499 -0
  10. package/docs/bundler/loaders.mdx +356 -0
  11. package/docs/bundler/macros.mdx +328 -0
  12. package/docs/bundler/minifier.mdx +1306 -0
  13. package/docs/bundler/plugins.mdx +411 -0
  14. package/docs/feedback.mdx +85 -0
  15. package/docs/guides/binary/arraybuffer-to-array.mdx +29 -0
  16. package/docs/guides/binary/arraybuffer-to-blob.mdx +26 -0
  17. package/docs/guides/binary/arraybuffer-to-buffer.mdx +27 -0
  18. package/docs/guides/binary/arraybuffer-to-string.mdx +17 -0
  19. package/docs/guides/binary/arraybuffer-to-typedarray.mdx +41 -0
  20. package/docs/guides/binary/blob-to-arraybuffer.mdx +16 -0
  21. package/docs/guides/binary/blob-to-dataview.mdx +16 -0
  22. package/docs/guides/binary/blob-to-stream.mdx +16 -0
  23. package/docs/guides/binary/blob-to-string.mdx +17 -0
  24. package/docs/guides/binary/blob-to-typedarray.mdx +16 -0
  25. package/docs/guides/binary/buffer-to-arraybuffer.mdx +16 -0
  26. package/docs/guides/binary/buffer-to-blob.mdx +16 -0
  27. package/docs/guides/binary/buffer-to-readablestream.mdx +43 -0
  28. package/docs/guides/binary/buffer-to-string.mdx +27 -0
  29. package/docs/guides/binary/buffer-to-typedarray.mdx +16 -0
  30. package/docs/guides/binary/dataview-to-string.mdx +17 -0
  31. package/docs/guides/binary/typedarray-to-arraybuffer.mdx +27 -0
  32. package/docs/guides/binary/typedarray-to-blob.mdx +18 -0
  33. package/docs/guides/binary/typedarray-to-buffer.mdx +16 -0
  34. package/docs/guides/binary/typedarray-to-dataview.mdx +16 -0
  35. package/docs/guides/binary/typedarray-to-readablestream.mdx +43 -0
  36. package/docs/guides/binary/typedarray-to-string.mdx +18 -0
  37. package/docs/guides/deployment/aws-lambda.mdx +204 -0
  38. package/docs/guides/deployment/digital-ocean.mdx +161 -0
  39. package/docs/guides/deployment/google-cloud-run.mdx +197 -0
  40. package/docs/guides/deployment/railway.mdx +145 -0
  41. package/docs/guides/deployment/render.mdx +82 -0
  42. package/docs/guides/deployment/vercel.mdx +99 -0
  43. package/docs/guides/ecosystem/astro.mdx +82 -0
  44. package/docs/guides/ecosystem/discordjs.mdx +80 -0
  45. package/docs/guides/ecosystem/docker.mdx +151 -0
  46. package/docs/guides/ecosystem/drizzle.mdx +195 -0
  47. package/docs/guides/ecosystem/edgedb.mdx +257 -0
  48. package/docs/guides/ecosystem/elysia.mdx +31 -0
  49. package/docs/guides/ecosystem/express.mdx +43 -0
  50. package/docs/guides/ecosystem/hono.mdx +47 -0
  51. package/docs/guides/ecosystem/mongoose.mdx +92 -0
  52. package/docs/guides/ecosystem/neon-drizzle.mdx +234 -0
  53. package/docs/guides/ecosystem/neon-serverless-postgres.mdx +60 -0
  54. package/docs/guides/ecosystem/nextjs.mdx +57 -0
  55. package/docs/guides/ecosystem/nuxt.mdx +90 -0
  56. package/docs/guides/ecosystem/pm2.mdx +55 -0
  57. package/docs/guides/ecosystem/prisma-postgres.mdx +169 -0
  58. package/docs/guides/ecosystem/prisma.mdx +164 -0
  59. package/docs/guides/ecosystem/qwik.mdx +114 -0
  60. package/docs/guides/ecosystem/react.mdx +52 -0
  61. package/docs/guides/ecosystem/remix.mdx +97 -0
  62. package/docs/guides/ecosystem/sentry.mdx +54 -0
  63. package/docs/guides/ecosystem/solidstart.mdx +66 -0
  64. package/docs/guides/ecosystem/ssr-react.mdx +49 -0
  65. package/docs/guides/ecosystem/stric.mdx +54 -0
  66. package/docs/guides/ecosystem/sveltekit.mdx +138 -0
  67. package/docs/guides/ecosystem/systemd.mdx +114 -0
  68. package/docs/guides/ecosystem/upstash.mdx +87 -0
  69. package/docs/guides/ecosystem/vite.mdx +77 -0
  70. package/docs/guides/html-rewriter/extract-links.mdx +72 -0
  71. package/docs/guides/html-rewriter/extract-social-meta.mdx +97 -0
  72. package/docs/guides/http/cluster.mdx +69 -0
  73. package/docs/guides/http/fetch-unix.mdx +35 -0
  74. package/docs/guides/http/fetch.mdx +26 -0
  75. package/docs/guides/http/file-uploads.mdx +97 -0
  76. package/docs/guides/http/hot.mdx +28 -0
  77. package/docs/guides/http/proxy.mdx +26 -0
  78. package/docs/guides/http/server.mdx +48 -0
  79. package/docs/guides/http/simple.mdx +20 -0
  80. package/docs/guides/http/stream-file.mdx +50 -0
  81. package/docs/guides/http/stream-iterator.mdx +49 -0
  82. package/docs/guides/http/stream-node-streams-in-bun.mdx +22 -0
  83. package/docs/guides/http/tls.mdx +32 -0
  84. package/docs/guides/index.mdx +10 -0
  85. package/docs/guides/install/add-dev.mdx +28 -0
  86. package/docs/guides/install/add-git.mdx +38 -0
  87. package/docs/guides/install/add-optional.mdx +27 -0
  88. package/docs/guides/install/add-peer.mdx +45 -0
  89. package/docs/guides/install/add-tarball.mdx +35 -0
  90. package/docs/guides/install/add.mdx +44 -0
  91. package/docs/guides/install/azure-artifacts.mdx +76 -0
  92. package/docs/guides/install/cicd.mdx +43 -0
  93. package/docs/guides/install/custom-registry.mdx +32 -0
  94. package/docs/guides/install/from-npm-install-to-bun-install.mdx +230 -0
  95. package/docs/guides/install/git-diff-bun-lockfile.mdx +47 -0
  96. package/docs/guides/install/jfrog-artifactory.mdx +28 -0
  97. package/docs/guides/install/npm-alias.mdx +25 -0
  98. package/docs/guides/install/registry-scope.mdx +40 -0
  99. package/docs/guides/install/trusted.mdx +50 -0
  100. package/docs/guides/install/workspaces.mdx +70 -0
  101. package/docs/guides/install/yarnlock.mdx +50 -0
  102. package/docs/guides/process/argv.mdx +66 -0
  103. package/docs/guides/process/ctrl-c.mdx +18 -0
  104. package/docs/guides/process/ipc.mdx +69 -0
  105. package/docs/guides/process/nanoseconds.mdx +15 -0
  106. package/docs/guides/process/os-signals.mdx +41 -0
  107. package/docs/guides/process/spawn-stderr.mdx +34 -0
  108. package/docs/guides/process/spawn-stdout.mdx +28 -0
  109. package/docs/guides/process/spawn.mdx +43 -0
  110. package/docs/guides/process/stdin.mdx +62 -0
  111. package/docs/guides/read-file/arraybuffer.mdx +30 -0
  112. package/docs/guides/read-file/buffer.mdx +21 -0
  113. package/docs/guides/read-file/exists.mdx +18 -0
  114. package/docs/guides/read-file/json.mdx +19 -0
  115. package/docs/guides/read-file/mime.mdx +22 -0
  116. package/docs/guides/read-file/stream.mdx +28 -0
  117. package/docs/guides/read-file/string.mdx +24 -0
  118. package/docs/guides/read-file/uint8array.mdx +23 -0
  119. package/docs/guides/read-file/watch.mdx +66 -0
  120. package/docs/guides/runtime/build-time-constants.mdx +295 -0
  121. package/docs/guides/runtime/cicd.mdx +45 -0
  122. package/docs/guides/runtime/codesign-macos-executable.mdx +61 -0
  123. package/docs/guides/runtime/define-constant.mdx +149 -0
  124. package/docs/guides/runtime/delete-directory.mdx +39 -0
  125. package/docs/guides/runtime/delete-file.mdx +21 -0
  126. package/docs/guides/runtime/heap-snapshot.mdx +28 -0
  127. package/docs/guides/runtime/import-html.mdx +17 -0
  128. package/docs/guides/runtime/import-json.mdx +46 -0
  129. package/docs/guides/runtime/import-toml.mdx +32 -0
  130. package/docs/guides/runtime/import-yaml.mdx +104 -0
  131. package/docs/guides/runtime/read-env.mdx +37 -0
  132. package/docs/guides/runtime/set-env.mdx +51 -0
  133. package/docs/guides/runtime/shell.mdx +42 -0
  134. package/docs/guides/runtime/timezone.mdx +38 -0
  135. package/docs/guides/runtime/tsconfig-paths.mdx +31 -0
  136. package/docs/guides/runtime/typescript.mdx +51 -0
  137. package/docs/guides/runtime/vscode-debugger.mdx +48 -0
  138. package/docs/guides/runtime/web-debugger.mdx +103 -0
  139. package/docs/guides/streams/node-readable-to-arraybuffer.mdx +13 -0
  140. package/docs/guides/streams/node-readable-to-blob.mdx +13 -0
  141. package/docs/guides/streams/node-readable-to-json.mdx +14 -0
  142. package/docs/guides/streams/node-readable-to-string.mdx +14 -0
  143. package/docs/guides/streams/node-readable-to-uint8array.mdx +13 -0
  144. package/docs/guides/streams/to-array.mdx +16 -0
  145. package/docs/guides/streams/to-arraybuffer.mdx +16 -0
  146. package/docs/guides/streams/to-blob.mdx +16 -0
  147. package/docs/guides/streams/to-buffer.mdx +17 -0
  148. package/docs/guides/streams/to-json.mdx +16 -0
  149. package/docs/guides/streams/to-string.mdx +16 -0
  150. package/docs/guides/streams/to-typedarray.mdx +24 -0
  151. package/docs/guides/test/bail.mdx +24 -0
  152. package/docs/guides/test/coverage-threshold.mdx +67 -0
  153. package/docs/guides/test/coverage.mdx +49 -0
  154. package/docs/guides/test/happy-dom.mdx +73 -0
  155. package/docs/guides/test/migrate-from-jest.mdx +125 -0
  156. package/docs/guides/test/mock-clock.mdx +50 -0
  157. package/docs/guides/test/mock-functions.mdx +70 -0
  158. package/docs/guides/test/rerun-each.mdx +16 -0
  159. package/docs/guides/test/run-tests.mdx +116 -0
  160. package/docs/guides/test/skip-tests.mdx +43 -0
  161. package/docs/guides/test/snapshot.mdx +102 -0
  162. package/docs/guides/test/spy-on.mdx +49 -0
  163. package/docs/guides/test/svelte-test.mdx +113 -0
  164. package/docs/guides/test/testing-library.mdx +93 -0
  165. package/docs/guides/test/timeout.mdx +17 -0
  166. package/docs/guides/test/todo-tests.mdx +74 -0
  167. package/docs/guides/test/update-snapshots.mdx +49 -0
  168. package/docs/guides/test/watch-mode.mdx +24 -0
  169. package/docs/guides/util/base64.mdx +17 -0
  170. package/docs/guides/util/deep-equals.mdx +41 -0
  171. package/docs/guides/util/deflate.mdx +20 -0
  172. package/docs/guides/util/detect-bun.mdx +25 -0
  173. package/docs/guides/util/entrypoint.mdx +19 -0
  174. package/docs/guides/util/escape-html.mdx +24 -0
  175. package/docs/guides/util/file-url-to-path.mdx +16 -0
  176. package/docs/guides/util/gzip.mdx +20 -0
  177. package/docs/guides/util/hash-a-password.mdx +56 -0
  178. package/docs/guides/util/import-meta-dir.mdx +15 -0
  179. package/docs/guides/util/import-meta-file.mdx +15 -0
  180. package/docs/guides/util/import-meta-path.mdx +15 -0
  181. package/docs/guides/util/javascript-uuid.mdx +25 -0
  182. package/docs/guides/util/main.mdx +43 -0
  183. package/docs/guides/util/path-to-file-url.mdx +16 -0
  184. package/docs/guides/util/sleep.mdx +24 -0
  185. package/docs/guides/util/version.mdx +23 -0
  186. package/docs/guides/util/which-path-to-executable-bin.mdx +17 -0
  187. package/docs/guides/websocket/compression.mdx +33 -0
  188. package/docs/guides/websocket/context.mdx +74 -0
  189. package/docs/guides/websocket/pubsub.mdx +40 -0
  190. package/docs/guides/websocket/simple.mdx +35 -0
  191. package/docs/guides/write-file/append.mdx +54 -0
  192. package/docs/guides/write-file/basic.mdx +46 -0
  193. package/docs/guides/write-file/blob.mdx +30 -0
  194. package/docs/guides/write-file/cat.mdx +19 -0
  195. package/docs/guides/write-file/file-cp.mdx +18 -0
  196. package/docs/guides/write-file/filesink.mdx +54 -0
  197. package/docs/guides/write-file/response.mdx +19 -0
  198. package/docs/guides/write-file/stdout.mdx +23 -0
  199. package/docs/guides/write-file/stream.mdx +19 -0
  200. package/docs/guides/write-file/unlink.mdx +18 -0
  201. package/docs/index.mdx +133 -0
  202. package/docs/installation.mdx +365 -0
  203. package/docs/pm/bunx.mdx +83 -0
  204. package/docs/pm/catalogs.mdx +292 -0
  205. package/docs/pm/cli/add.mdx +179 -0
  206. package/docs/pm/cli/audit.mdx +60 -0
  207. package/docs/pm/cli/install.mdx +471 -0
  208. package/docs/pm/cli/link.mdx +48 -0
  209. package/docs/pm/cli/outdated.mdx +197 -0
  210. package/docs/pm/cli/patch.mdx +69 -0
  211. package/docs/pm/cli/pm.mdx +319 -0
  212. package/docs/pm/cli/publish.mdx +123 -0
  213. package/docs/pm/cli/remove.mdx +16 -0
  214. package/docs/pm/cli/update.mdx +140 -0
  215. package/docs/pm/cli/why.mdx +84 -0
  216. package/docs/pm/filter.mdx +102 -0
  217. package/docs/pm/global-cache.mdx +72 -0
  218. package/docs/pm/isolated-installs.mdx +205 -0
  219. package/docs/pm/lifecycle.mdx +57 -0
  220. package/docs/pm/lockfile.mdx +64 -0
  221. package/docs/pm/npmrc.mdx +111 -0
  222. package/docs/pm/overrides.mdx +83 -0
  223. package/docs/pm/scopes-registries.mdx +35 -0
  224. package/docs/pm/security-scanner-api.mdx +95 -0
  225. package/docs/pm/workspaces.mdx +109 -0
  226. package/docs/project/benchmarking.mdx +218 -0
  227. package/docs/project/bindgen.mdx +223 -0
  228. package/docs/project/building-windows.mdx +133 -0
  229. package/docs/project/contributing.mdx +343 -0
  230. package/docs/project/feedback.mdx +20 -0
  231. package/docs/project/license.mdx +78 -0
  232. package/docs/project/roadmap.mdx +8 -0
  233. package/docs/quickstart.mdx +240 -0
  234. package/docs/runtime/auto-install.mdx +97 -0
  235. package/docs/runtime/binary-data.mdx +846 -0
  236. package/docs/runtime/bun-apis.mdx +59 -0
  237. package/docs/runtime/bunfig.mdx +642 -0
  238. package/docs/runtime/c-compiler.mdx +204 -0
  239. package/docs/runtime/child-process.mdx +532 -0
  240. package/docs/runtime/color.mdx +267 -0
  241. package/docs/runtime/console.mdx +67 -0
  242. package/docs/runtime/cookies.mdx +454 -0
  243. package/docs/runtime/debugger.mdx +335 -0
  244. package/docs/runtime/environment-variables.mdx +214 -0
  245. package/docs/runtime/ffi.mdx +565 -0
  246. package/docs/runtime/file-io.mdx +306 -0
  247. package/docs/runtime/file-system-router.mdx +118 -0
  248. package/docs/runtime/file-types.mdx +354 -0
  249. package/docs/runtime/glob.mdx +181 -0
  250. package/docs/runtime/globals.mdx +72 -0
  251. package/docs/runtime/hashing.mdx +315 -0
  252. package/docs/runtime/html-rewriter.mdx +340 -0
  253. package/docs/runtime/http/cookies.mdx +79 -0
  254. package/docs/runtime/http/error-handling.mdx +40 -0
  255. package/docs/runtime/http/metrics.mdx +36 -0
  256. package/docs/runtime/http/routing.mdx +289 -0
  257. package/docs/runtime/http/server.mdx +647 -0
  258. package/docs/runtime/http/tls.mdx +101 -0
  259. package/docs/runtime/http/websockets.mdx +404 -0
  260. package/docs/runtime/index.mdx +223 -0
  261. package/docs/runtime/jsx.mdx +115 -0
  262. package/docs/runtime/module-resolution.mdx +342 -0
  263. package/docs/runtime/networking/dns.mdx +111 -0
  264. package/docs/runtime/networking/fetch.mdx +468 -0
  265. package/docs/runtime/networking/tcp.mdx +239 -0
  266. package/docs/runtime/networking/udp.mdx +129 -0
  267. package/docs/runtime/node-api.mdx +19 -0
  268. package/docs/runtime/nodejs-compat.mdx +468 -0
  269. package/docs/runtime/plugins.mdx +405 -0
  270. package/docs/runtime/redis.mdx +582 -0
  271. package/docs/runtime/s3.mdx +863 -0
  272. package/docs/runtime/secrets.mdx +336 -0
  273. package/docs/runtime/semver.mdx +57 -0
  274. package/docs/runtime/shell.mdx +637 -0
  275. package/docs/runtime/sql.mdx +1404 -0
  276. package/docs/runtime/sqlite.mdx +699 -0
  277. package/docs/runtime/streams.mdx +232 -0
  278. package/docs/runtime/templating/create.mdx +269 -0
  279. package/docs/runtime/templating/init.mdx +58 -0
  280. package/docs/runtime/transpiler.mdx +288 -0
  281. package/docs/runtime/typescript.mdx +58 -0
  282. package/docs/runtime/utils.mdx +922 -0
  283. package/docs/runtime/watch-mode.mdx +161 -0
  284. package/docs/runtime/web-apis.mdx +29 -0
  285. package/docs/runtime/workers.mdx +328 -0
  286. package/docs/runtime/yaml.mdx +469 -0
  287. package/docs/snippets/cli/add.mdx +166 -0
  288. package/docs/snippets/cli/build.mdx +196 -0
  289. package/docs/snippets/cli/feedback.mdx +17 -0
  290. package/docs/snippets/cli/init.mdx +84 -0
  291. package/docs/snippets/cli/install.mdx +173 -0
  292. package/docs/snippets/cli/link.mdx +163 -0
  293. package/docs/snippets/cli/outdated.mdx +140 -0
  294. package/docs/snippets/cli/patch.mdx +171 -0
  295. package/docs/snippets/cli/publish.mdx +198 -0
  296. package/docs/snippets/cli/remove.mdx +146 -0
  297. package/docs/snippets/cli/run.mdx +293 -0
  298. package/docs/snippets/cli/test.mdx +100 -0
  299. package/docs/snippets/cli/update.mdx +144 -0
  300. package/docs/snippets/product-card.mdx +32 -0
  301. package/docs/snippets/product-tiles.mdx +94 -0
  302. package/docs/test/code-coverage.mdx +409 -0
  303. package/docs/test/configuration.mdx +467 -0
  304. package/docs/test/dates-times.mdx +129 -0
  305. package/docs/test/discovery.mdx +90 -0
  306. package/docs/test/dom.mdx +226 -0
  307. package/docs/test/index.mdx +380 -0
  308. package/docs/test/lifecycle.mdx +348 -0
  309. package/docs/test/mocks.mdx +637 -0
  310. package/docs/test/reporters.mdx +117 -0
  311. package/docs/test/runtime-behavior.mdx +342 -0
  312. package/docs/test/snapshots.mdx +434 -0
  313. package/docs/test/writing-tests.mdx +635 -0
  314. package/docs/typescript.mdx +54 -0
  315. package/package.json +8 -6
  316. package/test.d.ts +2 -2
@@ -0,0 +1,863 @@
1
+ ---
2
+ title: S3
3
+ description: Bun provides fast, native bindings for interacting with S3-compatible object storage services.
4
+ ---
5
+
6
+ Production servers often read, upload, and write files to S3-compatible object storage services instead of the local filesystem. Historically, that means local filesystem APIs you use in development can't be used in production. When you use Bun, things are different.
7
+
8
+ ### Bun's S3 API is fast
9
+
10
+ <Frame caption="Left: Bun v1.1.44. Right: Node.js v23.6.0">
11
+ <img src="/images/bun-s3-node.gif" alt="Bun's S3 API is fast" />
12
+ </Frame>
13
+
14
+ Bun provides fast, native bindings for interacting with S3-compatible object storage services. Bun's S3 API is designed to be simple and feel similar to fetch's `Response` and `Blob` APIs (like Bun's local filesystem APIs).
15
+
16
+ ```ts s3.ts icon="/icons/typescript.svg"
17
+ import { s3, write, S3Client } from "bun";
18
+
19
+ // Bun.s3 reads environment variables for credentials
20
+ // file() returns a lazy reference to a file on S3
21
+ const metadata = s3.file("123.json");
22
+
23
+ // Download from S3 as JSON
24
+ const data = await metadata.json();
25
+
26
+ // Upload to S3
27
+ await write(metadata, JSON.stringify({ name: "John", age: 30 }));
28
+
29
+ // Presign a URL (synchronous - no network request needed)
30
+ const url = metadata.presign({
31
+ acl: "public-read",
32
+ expiresIn: 60 * 60 * 24, // 1 day
33
+ });
34
+
35
+ // Delete the file
36
+ await metadata.delete();
37
+ ```
38
+
39
+ S3 is the [de facto standard](https://en.wikipedia.org/wiki/De_facto_standard) internet filesystem. Bun's S3 API works with S3-compatible storage services like:
40
+
41
+ - AWS S3
42
+ - Cloudflare R2
43
+ - DigitalOcean Spaces
44
+ - MinIO
45
+ - Backblaze B2
46
+ - ...and any other S3-compatible storage service
47
+
48
+ ## Basic Usage
49
+
50
+ There are several ways to interact with Bun's S3 API.
51
+
52
+ ### `Bun.S3Client` & `Bun.s3`
53
+
54
+ `Bun.s3` is equivalent to `new Bun.S3Client()`, relying on environment variables for credentials.
55
+
56
+ To explicitly set credentials, pass them to the `Bun.S3Client` constructor.
57
+
58
+ ```ts s3.ts icon="/icons/typescript.svg"
59
+ import { S3Client } from "bun";
60
+
61
+ const client = new S3Client({
62
+ accessKeyId: "your-access-key",
63
+ secretAccessKey: "your-secret-key",
64
+ bucket: "my-bucket",
65
+ // sessionToken: "..."
66
+ // acl: "public-read",
67
+ // endpoint: "https://s3.us-east-1.amazonaws.com",
68
+ // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
69
+ // endpoint: "https://<region>.digitaloceanspaces.com", // DigitalOcean Spaces
70
+ // endpoint: "http://localhost:9000", // MinIO
71
+ });
72
+
73
+ // Bun.s3 is a global singleton that is equivalent to `new Bun.S3Client()`
74
+ ```
75
+
76
+ ### Working with S3 Files
77
+
78
+ The **`file`** method in `S3Client` returns a **lazy reference to a file on S3**.
79
+
80
+ ```ts s3.ts icon="/icons/typescript.svg"
81
+ // A lazy reference to a file on S3
82
+ const s3file: S3File = client.file("123.json");
83
+ ```
84
+
85
+ Like `Bun.file(path)`, the `S3Client`'s `file` method is synchronous. It does zero network requests until you call a method that depends on a network request.
86
+
87
+ ### Reading files from S3
88
+
89
+ If you've used the `fetch` API, you're familiar with the `Response` and `Blob` APIs. `S3File` extends `Blob`. The same methods that work on `Blob` also work on `S3File`.
90
+
91
+ ```ts s3.ts icon="/icons/typescript.svg"
92
+ // Read an S3File as text
93
+ const text = await s3file.text();
94
+
95
+ // Read an S3File as JSON
96
+ const json = await s3file.json();
97
+
98
+ // Read an S3File as an ArrayBuffer
99
+ const buffer = await s3file.arrayBuffer();
100
+
101
+ // Get only the first 1024 bytes
102
+ const partial = await s3file.slice(0, 1024).text();
103
+
104
+ // Stream the file
105
+ const stream = s3file.stream();
106
+ for await (const chunk of stream) {
107
+ console.log(chunk);
108
+ }
109
+ ```
110
+
111
+ #### Memory optimization
112
+
113
+ Methods like `text()`, `json()`, `bytes()`, or `arrayBuffer()` avoid duplicating the string or bytes in memory when possible.
114
+
115
+ If the text happens to be ASCII, Bun directly transfers the string to JavaScriptCore (the engine) without transcoding and without duplicating the string in memory. When you use `.bytes()` or `.arrayBuffer()`, it will also avoid duplicating the bytes in memory.
116
+
117
+ These helper methods not only simplify the API, they also make it faster.
118
+
119
+ ### Writing & uploading files to S3
120
+
121
+ Writing to S3 is just as simple.
122
+
123
+ ```ts s3.ts icon="/icons/typescript.svg"
124
+ // Write a string (replacing the file)
125
+ await s3file.write("Hello World!");
126
+
127
+ // Write a Buffer (replacing the file)
128
+ await s3file.write(Buffer.from("Hello World!"));
129
+
130
+ // Write a Response (replacing the file)
131
+ await s3file.write(new Response("Hello World!"));
132
+
133
+ // Write with content type
134
+ await s3file.write(JSON.stringify({ name: "John", age: 30 }), {
135
+ type: "application/json",
136
+ });
137
+
138
+ // Write using a writer (streaming)
139
+ const writer = s3file.writer({ type: "application/json" });
140
+ writer.write("Hello");
141
+ writer.write(" World!");
142
+ await writer.end();
143
+
144
+ // Write using Bun.write
145
+ await Bun.write(s3file, "Hello World!");
146
+ ```
147
+
148
+ ### Working with large files (streams)
149
+
150
+ Bun automatically handles multipart uploads for large files and provides streaming capabilities. The same API that works for local files also works for S3 files.
151
+
152
+ ```ts s3.ts icon="/icons/typescript.svg"
153
+ // Write a large file
154
+ const bigFile = Buffer.alloc(10 * 1024 * 1024); // 10MB
155
+ const writer = s3file.writer({
156
+ // Automatically retry on network errors up to 3 times
157
+ retry: 3,
158
+
159
+ // Queue up to 10 requests at a time
160
+ queueSize: 10,
161
+
162
+ // Upload in 5 MB chunks
163
+ partSize: 5 * 1024 * 1024,
164
+ });
165
+ for (let i = 0; i < 10; i++) {
166
+ writer.write(bigFile);
167
+ await writer.flush();
168
+ }
169
+ await writer.end();
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Presigning URLs
175
+
176
+ When your production service needs to let users upload files to your server, it's often more reliable for the user to upload directly to S3 instead of your server acting as an intermediary.
177
+
178
+ To facilitate this, you can presign URLs for S3 files. This generates a URL with a signature that allows a user to securely upload that specific file to S3, without exposing your credentials or granting them unnecessary access to your bucket.
179
+
180
+ The default behaviour is to generate a `GET` URL that expires in 24 hours. Bun attempts to infer the content type from the file extension. If inference is not possible, it will default to `application/octet-stream`.
181
+
182
+ ```ts s3.ts icon="/icons/typescript.svg"
183
+ import { s3 } from "bun";
184
+
185
+ // Generate a presigned URL that expires in 24 hours (default)
186
+ const download = s3.presign("my-file.txt"); // GET, text/plain, expires in 24 hours
187
+
188
+ const upload = s3.presign("my-file", {
189
+ expiresIn: 3600, // 1 hour
190
+ method: "PUT",
191
+ type: "application/json", // No extension for inferring, so we can specify the content type to be JSON
192
+ });
193
+
194
+ // You can call .presign() if on a file reference, but avoid doing so
195
+ // unless you already have a reference (to avoid memory usage).
196
+ const myFile = s3.file("my-file.txt");
197
+ const presignedFile = myFile.presign({
198
+ expiresIn: 3600, // 1 hour
199
+ });
200
+ ```
201
+
202
+ ### Setting ACLs
203
+
204
+ To set an ACL (access control list) on a presigned URL, pass the `acl` option:
205
+
206
+ ```ts s3.ts icon="/icons/typescript.svg"
207
+ const url = s3file.presign({
208
+ acl: "public-read",
209
+ expiresIn: 3600,
210
+ });
211
+ ```
212
+
213
+ You can pass any of the following ACLs:
214
+
215
+ | ACL | Explanation |
216
+ | ----------------------------- | ------------------------------------------------------------------- |
217
+ | `"public-read"` | The object is readable by the public. |
218
+ | `"private"` | The object is readable only by the bucket owner. |
219
+ | `"public-read-write"` | The object is readable and writable by the public. |
220
+ | `"authenticated-read"` | The object is readable by the bucket owner and authenticated users. |
221
+ | `"aws-exec-read"` | The object is readable by the AWS account that made the request. |
222
+ | `"bucket-owner-read"` | The object is readable by the bucket owner. |
223
+ | `"bucket-owner-full-control"` | The object is readable and writable by the bucket owner. |
224
+ | `"log-delivery-write"` | The object is writable by AWS services used for log delivery. |
225
+
226
+ ### Expiring URLs
227
+
228
+ To set an expiration time for a presigned URL, pass the `expiresIn` option.
229
+
230
+ ```ts s3.ts icon="/icons/typescript.svg"
231
+ const url = s3file.presign({
232
+ // Seconds
233
+ expiresIn: 3600, // 1 hour
234
+
235
+ // access control list
236
+ acl: "public-read",
237
+
238
+ // HTTP method
239
+ method: "PUT",
240
+ });
241
+ ```
242
+
243
+ ### `method`
244
+
245
+ To set the HTTP method for a presigned URL, pass the `method` option.
246
+
247
+ ```ts s3.ts icon="/icons/typescript.svg"
248
+ const url = s3file.presign({
249
+ method: "PUT",
250
+ // method: "DELETE",
251
+ // method: "GET",
252
+ // method: "HEAD",
253
+ // method: "POST",
254
+ // method: "PUT",
255
+ });
256
+ ```
257
+
258
+ ### `new Response(S3File)`
259
+
260
+ To quickly redirect users to a presigned URL for an S3 file, pass an `S3File` instance to a `Response` object as the body.
261
+
262
+ This will automatically redirect the user to the presigned URL for the S3 file, saving you the memory, time, and bandwidth cost of downloading the file to your server and sending it back to the user.
263
+
264
+ ```ts s3.ts icon="/icons/typescript.svg"
265
+ const response = new Response(s3file);
266
+ console.log(response);
267
+ ```
268
+
269
+ ```txt
270
+ Response (0 KB) {
271
+ ok: false,
272
+ url: "",
273
+ status: 302,
274
+ statusText: "",
275
+ headers: Headers {
276
+ "location": "https://<account-id>.r2.cloudflarestorage.com/...",
277
+ },
278
+ redirected: true,
279
+ bodyUsed: false
280
+ }
281
+ ```
282
+
283
+ ---
284
+
285
+ ## Support for S3-Compatible Services
286
+
287
+ Bun's S3 implementation works with any S3-compatible storage service. Just specify the appropriate endpoint:
288
+
289
+ ### Using Bun's S3Client with AWS S3
290
+
291
+ AWS S3 is the default. You can also pass a `region` option instead of an `endpoint` option for AWS S3.
292
+
293
+ ```ts s3.ts icon="/icons/typescript.svg"
294
+ import { S3Client } from "bun";
295
+
296
+ // AWS S3
297
+ const s3 = new S3Client({
298
+ accessKeyId: "access-key",
299
+ secretAccessKey: "secret-key",
300
+ bucket: "my-bucket",
301
+ // endpoint: "https://s3.us-east-1.amazonaws.com",
302
+ // region: "us-east-1",
303
+ });
304
+ ```
305
+
306
+ ### Using Bun's S3Client with Google Cloud Storage
307
+
308
+ To use Bun's S3 client with [Google Cloud Storage](https://cloud.google.com/storage), set `endpoint` to `"https://storage.googleapis.com"` in the `S3Client` constructor.
309
+
310
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={8}
311
+ import { S3Client } from "bun";
312
+
313
+ // Google Cloud Storage
314
+ const gcs = new S3Client({
315
+ accessKeyId: "access-key",
316
+ secretAccessKey: "secret-key",
317
+ bucket: "my-bucket",
318
+ endpoint: "https://storage.googleapis.com",
319
+ });
320
+ ```
321
+
322
+ ### Using Bun's S3Client with Cloudflare R2
323
+
324
+ To use Bun's S3 client with [Cloudflare R2](https://developers.cloudflare.com/r2/), set `endpoint` to the R2 endpoint in the `S3Client` constructor. The R2 endpoint includes your account ID.
325
+
326
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={8}
327
+ import { S3Client } from "bun";
328
+
329
+ // CloudFlare R2
330
+ const r2 = new S3Client({
331
+ accessKeyId: "access-key",
332
+ secretAccessKey: "secret-key",
333
+ bucket: "my-bucket",
334
+ endpoint: "https://<account-id>.r2.cloudflarestorage.com",
335
+ });
336
+ ```
337
+
338
+ ### Using Bun's S3Client with DigitalOcean Spaces
339
+
340
+ To use Bun's S3 client with [DigitalOcean Spaces](https://www.digitalocean.com/products/spaces/), set `endpoint` to the DigitalOcean Spaces endpoint in the `S3Client` constructor.
341
+
342
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={8}
343
+ import { S3Client } from "bun";
344
+
345
+ const spaces = new S3Client({
346
+ accessKeyId: "access-key",
347
+ secretAccessKey: "secret-key",
348
+ bucket: "my-bucket",
349
+ // region: "nyc3",
350
+ endpoint: "https://<region>.digitaloceanspaces.com",
351
+ });
352
+ ```
353
+
354
+ ### Using Bun's S3Client with MinIO
355
+
356
+ To use Bun's S3 client with [MinIO](https://min.io/), set `endpoint` to the URL that MinIO is running on in the `S3Client` constructor.
357
+
358
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={10}
359
+ import { S3Client } from "bun";
360
+
361
+ const minio = new S3Client({
362
+ accessKeyId: "access-key",
363
+ secretAccessKey: "secret-key",
364
+ bucket: "my-bucket",
365
+
366
+ // Make sure to use the correct endpoint URL
367
+ // It might not be localhost in production!
368
+ endpoint: "http://localhost:9000",
369
+ });
370
+ ```
371
+
372
+ ### Using Bun's S3Client with supabase
373
+
374
+ To use Bun's S3 client with [supabase](https://supabase.com/), set `endpoint` to the supabase endpoint in the `S3Client` constructor. The supabase endpoint includes your account ID and /storage/v1/s3 path. Make sure to set Enable connection via S3 protocol on in the supabase dashboard in `https://supabase.com/dashboard/project/<account-id>/settings/storage` and to set the region informed in the same section.
375
+
376
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={3-10}
377
+ import { S3Client } from "bun";
378
+
379
+ const supabase = new S3Client({
380
+ accessKeyId: "access-key",
381
+ secretAccessKey: "secret-key",
382
+ bucket: "my-bucket",
383
+ region: "us-west-1",
384
+ endpoint: "https://<account-id>.supabase.co/storage/v1/s3/storage",
385
+ });
386
+ ```
387
+
388
+ ### Using Bun's S3Client with S3 Virtual Hosted-Style endpoints
389
+
390
+ When using a S3 Virtual Hosted-Style endpoint, you need to set the `virtualHostedStyle` option to `true`.
391
+
392
+ <Note>
393
+ - If you don’t specify an endpoint, Bun will automatically determine the AWS S3 endpoint using the provided region and
394
+ bucket. - If no region is specified, Bun defaults to us-east-1. - If you explicitly provide an endpoint, you don’t
395
+ need to specify a bucket name.
396
+ </Note>
397
+
398
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={17, 25}
399
+ import { S3Client } from "bun";
400
+
401
+ // AWS S3 endpoint inferred from region and bucket
402
+ const s3 = new S3Client({
403
+ accessKeyId: "access-key",
404
+ secretAccessKey: "secret-key",
405
+ bucket: "my-bucket",
406
+ virtualHostedStyle: true, // [!code ++]
407
+ // endpoint: "https://my-bucket.s3.us-east-1.amazonaws.com",
408
+ // region: "us-east-1",
409
+ });
410
+
411
+ // AWS S3
412
+ const s3WithEndpoint = new S3Client({
413
+ accessKeyId: "access-key",
414
+ secretAccessKey: "secret-key",
415
+ endpoint: "https://<bucket-name>.s3.<region>.amazonaws.com",
416
+ virtualHostedStyle: true, // [!code ++]
417
+ });
418
+
419
+ // Cloudflare R2
420
+ const r2WithEndpoint = new S3Client({
421
+ accessKeyId: "access-key",
422
+ secretAccessKey: "secret-key",
423
+ endpoint: "https://<bucket-name>.<account-id>.r2.cloudflarestorage.com",
424
+ virtualHostedStyle: true, // [!code ++]
425
+ });
426
+ ```
427
+
428
+ ---
429
+
430
+ ## Credentials
431
+
432
+ Credentials are one of the hardest parts of using S3, and we've tried to make it as easy as possible. By default, Bun reads the following environment variables for credentials.
433
+
434
+ | Option name | Environment variable |
435
+ | ----------------- | ---------------------- |
436
+ | `accessKeyId` | `S3_ACCESS_KEY_ID` |
437
+ | `secretAccessKey` | `S3_SECRET_ACCESS_KEY` |
438
+ | `region` | `S3_REGION` |
439
+ | `endpoint` | `S3_ENDPOINT` |
440
+ | `bucket` | `S3_BUCKET` |
441
+ | `sessionToken` | `S3_SESSION_TOKEN` |
442
+
443
+ If the `S3_*` environment variable is not set, Bun will also check for the `AWS_*` environment variable, for each of the above options.
444
+
445
+ | Option name | Fallback environment variable |
446
+ | ----------------- | ----------------------------- |
447
+ | `accessKeyId` | `AWS_ACCESS_KEY_ID` |
448
+ | `secretAccessKey` | `AWS_SECRET_ACCESS_KEY` |
449
+ | `region` | `AWS_REGION` |
450
+ | `endpoint` | `AWS_ENDPOINT` |
451
+ | `bucket` | `AWS_BUCKET` |
452
+ | `sessionToken` | `AWS_SESSION_TOKEN` |
453
+
454
+ These environment variables are read from [`.env` files](/runtime/environment-variables) or from the process environment at initialization time (`process.env` is not used for this).
455
+
456
+ These defaults are overridden by the options you pass to `s3.file(credentials)`, `new Bun.S3Client(credentials)`, or any of the methods that accept credentials. So if, for example, you use the same credentials for different buckets, you can set the credentials once in your `.env` file and then pass `bucket: "my-bucket"` to the `s3.file()` function without having to specify all the credentials again.
457
+
458
+ ### `S3Client` objects
459
+
460
+ When you're not using environment variables or using multiple buckets, you can create a `S3Client` object to explicitly set credentials.
461
+
462
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={3-11}
463
+ import { S3Client } from "bun";
464
+
465
+ const client = new S3Client({
466
+ accessKeyId: "your-access-key",
467
+ secretAccessKey: "your-secret-key",
468
+ bucket: "my-bucket",
469
+ // sessionToken: "..."
470
+ endpoint: "https://s3.us-east-1.amazonaws.com",
471
+ // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
472
+ // endpoint: "http://localhost:9000", // MinIO
473
+ });
474
+
475
+ // Write using a Response
476
+ await file.write(new Response("Hello World!"));
477
+
478
+ // Presign a URL
479
+ const url = file.presign({
480
+ expiresIn: 60 * 60 * 24, // 1 day
481
+ acl: "public-read",
482
+ });
483
+
484
+ // Delete the file
485
+ await file.delete();
486
+ ```
487
+
488
+ ### `S3Client.prototype.write`
489
+
490
+ To upload or write a file to S3, call `write` on the `S3Client` instance.
491
+
492
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={8, 9}
493
+ const client = new Bun.S3Client({
494
+ accessKeyId: "your-access-key",
495
+ secretAccessKey: "your-secret-key",
496
+ endpoint: "https://s3.us-east-1.amazonaws.com",
497
+ bucket: "my-bucket",
498
+ });
499
+
500
+ await client.write("my-file.txt", "Hello World!");
501
+ await client.write("my-file.txt", new Response("Hello World!"));
502
+
503
+ // equivalent to
504
+ // await client.file("my-file.txt").write("Hello World!");
505
+ ```
506
+
507
+ ### `S3Client.prototype.delete`
508
+
509
+ To delete a file from S3, call `delete` on the `S3Client` instance.
510
+
511
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={7}
512
+ const client = new Bun.S3Client({
513
+ accessKeyId: "your-access-key",
514
+ secretAccessKey: "your-secret-key",
515
+ bucket: "my-bucket",
516
+ });
517
+
518
+ await client.delete("my-file.txt");
519
+ // equivalent to
520
+ // await client.file("my-file.txt").delete();
521
+ ```
522
+
523
+ ### `S3Client.prototype.exists`
524
+
525
+ To check if a file exists in S3, call `exists` on the `S3Client` instance.
526
+
527
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={7}
528
+ const client = new Bun.S3Client({
529
+ accessKeyId: "your-access-key",
530
+ secretAccessKey: "your-secret-key",
531
+ bucket: "my-bucket",
532
+ });
533
+
534
+ const exists = await client.exists("my-file.txt");
535
+ // equivalent to
536
+ // const exists = await client.file("my-file.txt").exists();
537
+ ```
538
+
539
+ ## `S3File`
540
+
541
+ `S3File` instances are created by calling the `S3Client` instance method or the `s3.file()` function. Like `Bun.file()`, `S3File` instances are lazy. They don't refer to something that necessarily exists at the time of creation. That's why all the methods that don't involve network requests are fully synchronous.
542
+
543
+ ```ts Type Reference icon="/icons/typescript.svg" expandable
544
+ interface S3File extends Blob {
545
+ slice(start: number, end?: number): S3File;
546
+ exists(): Promise<boolean>;
547
+ unlink(): Promise<void>;
548
+ presign(options: S3Options): string;
549
+ text(): Promise<string>;
550
+ json(): Promise<any>;
551
+ bytes(): Promise<Uint8Array>;
552
+ arrayBuffer(): Promise<ArrayBuffer>;
553
+ stream(options: S3Options): ReadableStream;
554
+ write(
555
+ data: string | Uint8Array | ArrayBuffer | Blob | ReadableStream | Response | Request,
556
+ options?: BlobPropertyBag,
557
+ ): Promise<number>;
558
+
559
+ exists(options?: S3Options): Promise<boolean>;
560
+ unlink(options?: S3Options): Promise<void>;
561
+ delete(options?: S3Options): Promise<void>;
562
+ presign(options?: S3Options): string;
563
+
564
+ stat(options?: S3Options): Promise<S3Stat>;
565
+ /**
566
+ * Size is not synchronously available because it requires a network request.
567
+ *
568
+ * @deprecated Use `stat()` instead.
569
+ */
570
+ size: NaN;
571
+
572
+ // ... more omitted for brevity
573
+ }
574
+ ```
575
+
576
+ Like `Bun.file()`, `S3File` extends [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob), so all the methods that are available on `Blob` are also available on `S3File`. The same API for reading data from a local file is also available for reading data from S3.
577
+
578
+ | Method | Output |
579
+ | ---------------------------- | ---------------- |
580
+ | `await s3File.text()` | `string` |
581
+ | `await s3File.bytes()` | `Uint8Array` |
582
+ | `await s3File.json()` | `JSON` |
583
+ | `await s3File.stream()` | `ReadableStream` |
584
+ | `await s3File.arrayBuffer()` | `ArrayBuffer` |
585
+
586
+ That means using `S3File` instances with `fetch()`, `Response`, and other web APIs that accept `Blob` instances just works.
587
+
588
+ ### Partial reads with `slice`
589
+
590
+ To read a partial range of a file, you can use the `slice` method.
591
+
592
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={1}
593
+ const partial = s3file.slice(0, 1024);
594
+
595
+ // Read the partial range as a Uint8Array
596
+ const bytes = await partial.bytes();
597
+
598
+ // Read the partial range as a string
599
+ const text = await partial.text();
600
+ ```
601
+
602
+ Internally, this works by using the HTTP `Range` header to request only the bytes you want. This `slice` method is the same as [`Blob.prototype.slice`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice).
603
+
604
+ ### Deleting files from S3
605
+
606
+ To delete a file from S3, you can use the `delete` method.
607
+
608
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={1}
609
+ await s3file.delete();
610
+ // await s3File.unlink();
611
+ ```
612
+
613
+ `delete` is the same as `unlink`.
614
+
615
+ ## Error codes
616
+
617
+ When Bun's S3 API throws an error, it will have a `code` property that matches one of the following values:
618
+
619
+ - `ERR_S3_MISSING_CREDENTIALS`
620
+ - `ERR_S3_INVALID_METHOD`
621
+ - `ERR_S3_INVALID_PATH`
622
+ - `ERR_S3_INVALID_ENDPOINT`
623
+ - `ERR_S3_INVALID_SIGNATURE`
624
+ - `ERR_S3_INVALID_SESSION_TOKEN`
625
+
626
+ When the S3 Object Storage service returns an error (that is, not Bun), it will be an `S3Error` instance (an `Error` instance with the name `"S3Error"`).
627
+
628
+ ## `S3Client` static methods
629
+
630
+ The `S3Client` class provides several static methods for interacting with S3.
631
+
632
+ ### `S3Client.write` (static)
633
+
634
+ To write data directly to a path in the bucket, you can use the `S3Client.write` static method.
635
+
636
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={12, 15-18, 22, 25-29}
637
+ import { S3Client } from "bun";
638
+
639
+ const credentials = {
640
+ accessKeyId: "your-access-key",
641
+ secretAccessKey: "your-secret-key",
642
+ bucket: "my-bucket",
643
+ // endpoint: "https://s3.us-east-1.amazonaws.com",
644
+ // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
645
+ };
646
+
647
+ // Write string
648
+ await S3Client.write("my-file.txt", "Hello World");
649
+
650
+ // Write JSON with type
651
+ await S3Client.write("data.json", JSON.stringify({ hello: "world" }), {
652
+ ...credentials,
653
+ type: "application/json",
654
+ });
655
+
656
+ // Write from fetch
657
+ const res = await fetch("https://example.com/data");
658
+ await S3Client.write("data.bin", res, credentials);
659
+
660
+ // Write with ACL
661
+ await S3Client.write("public.html", html, {
662
+ ...credentials,
663
+ acl: "public-read",
664
+ type: "text/html",
665
+ });
666
+ ```
667
+
668
+ This is equivalent to calling `new S3Client(credentials).write("my-file.txt", "Hello World")`.
669
+
670
+ ### `S3Client.presign` (static)
671
+
672
+ To generate a presigned URL for an S3 file, you can use the `S3Client.presign` static method.
673
+
674
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={11-14}
675
+ import { S3Client } from "bun";
676
+
677
+ const credentials = {
678
+ accessKeyId: "your-access-key",
679
+ secretAccessKey: "your-secret-key",
680
+ bucket: "my-bucket",
681
+ // endpoint: "https://s3.us-east-1.amazonaws.com",
682
+ // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
683
+ };
684
+
685
+ const url = S3Client.presign("my-file.txt", {
686
+ ...credentials,
687
+ expiresIn: 3600,
688
+ });
689
+ ```
690
+
691
+ This is equivalent to calling `new S3Client(credentials).presign("my-file.txt", { expiresIn: 3600 })`.
692
+
693
+ ### `S3Client.list` (static)
694
+
695
+ To list some or all (up to 1,000) objects in a bucket, you can use the `S3Client.list` static method.
696
+
697
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={12, 15-20, 24-29}
698
+ import { S3Client } from "bun";
699
+
700
+ const credentials = { ... }
701
+ accessKeyId: "your-access-key",
702
+ secretAccessKey: "your-secret-key",
703
+ bucket: "my-bucket",
704
+ // endpoint: "https://s3.us-east-1.amazonaws.com",
705
+ // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
706
+ };
707
+
708
+ // List (up to) 1000 objects in the bucket
709
+ const allObjects = await S3Client.list(null, credentials);
710
+
711
+ // List (up to) 500 objects under `uploads/` prefix, with owner field for each object
712
+ const uploads = await S3Client.list({
713
+ prefix: 'uploads/',
714
+ maxKeys: 500,
715
+ fetchOwner: true,
716
+ }, credentials);
717
+
718
+ // Check if more results are available
719
+ if (uploads.isTruncated) {
720
+ // List next batch of objects under `uploads/` prefix
721
+ const moreUploads = await S3Client.list({
722
+ prefix: 'uploads/',
723
+ maxKeys: 500,
724
+ startAfter: uploads.contents!.at(-1).key
725
+ fetchOwner: true,
726
+ }, credentials);
727
+ }
728
+ ```
729
+
730
+ This is equivalent to calling `new S3Client(credentials).list()`.
731
+
732
+ ### `S3Client.exists` (static)
733
+
734
+ To check if an S3 file exists, you can use the `S3Client.exists` static method.
735
+
736
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={11}
737
+ import { S3Client } from "bun";
738
+
739
+ const credentials = {
740
+ accessKeyId: "your-access-key",
741
+ secretAccessKey: "your-secret-key",
742
+ bucket: "my-bucket",
743
+ // endpoint: "https://s3.us-east-1.amazonaws.com",
744
+ // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
745
+ };
746
+
747
+ const exists = await S3Client.exists("my-file.txt", credentials);
748
+ ```
749
+
750
+ The same method also works on `S3File` instances.
751
+
752
+ ```ts s3.ts icon="/icons/typescript.svg" highlight=7}
753
+ import { s3 } from "bun";
754
+
755
+ const s3file = s3.file("my-file.txt", {
756
+ // ...credentials,
757
+ });
758
+
759
+ const exists = await s3file.exists();
760
+ ```
761
+
762
+ ### `S3Client.size` (static)
763
+
764
+ To quickly check the size of S3 file without downloading it, you can use the `S3Client.size` static method.
765
+
766
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={11}
767
+ import { S3Client } from "bun";
768
+
769
+ const credentials = {
770
+ accessKeyId: "your-access-key",
771
+ secretAccessKey: "your-secret-key",
772
+ bucket: "my-bucket",
773
+ // endpoint: "https://s3.us-east-1.amazonaws.com",
774
+ // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
775
+ };
776
+
777
+ const bytes = await S3Client.size("my-file.txt", credentials);
778
+ ```
779
+
780
+ This is equivalent to calling `new S3Client(credentials).size("my-file.txt")`.
781
+
782
+ ### `S3Client.stat` (static)
783
+
784
+ To get the size, etag, and other metadata of an S3 file, you can use the `S3Client.stat` static method.
785
+
786
+ ```ts s3.ts icon="/icons/typescript.svg"
787
+ import { S3Client } from "bun";
788
+
789
+ const credentials = {
790
+ accessKeyId: "your-access-key",
791
+ secretAccessKey: "your-secret-key",
792
+ bucket: "my-bucket",
793
+ // endpoint: "https://s3.us-east-1.amazonaws.com",
794
+ // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
795
+ };
796
+
797
+ const stat = await S3Client.stat("my-file.txt", credentials);
798
+ ```
799
+
800
+ ```txt
801
+ {
802
+ etag: "\"7a30b741503c0b461cc14157e2df4ad8\"",
803
+ lastModified: 2025-01-07T00:19:10.000Z,
804
+ size: 1024,
805
+ type: "text/plain;charset=utf-8",
806
+ }
807
+ ```
808
+
809
+ ### `S3Client.delete` (static)
810
+
811
+ To delete an S3 file, you can use the `S3Client.delete` static method.
812
+
813
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={10, 15}
814
+ import { S3Client } from "bun";
815
+
816
+ const credentials = {
817
+ accessKeyId: "your-access-key",
818
+ secretAccessKey: "your-secret-key",
819
+ bucket: "my-bucket",
820
+ // endpoint: "https://s3.us-east-1.amazonaws.com",
821
+ };
822
+
823
+ await S3Client.delete("my-file.txt", credentials);
824
+ // equivalent to
825
+ // await new S3Client(credentials).delete("my-file.txt");
826
+
827
+ // S3Client.unlink is alias of S3Client.delete
828
+ await S3Client.unlink("my-file.txt", credentials);
829
+ ```
830
+
831
+ ## `s3://` protocol
832
+
833
+ To make it easier to use the same code for local files and S3 files, the `s3://` protocol is supported in `fetch` and `Bun.file()`.
834
+
835
+ ```ts s3.ts icon="/icons/typescript.svg"
836
+ const response = await fetch("s3://my-bucket/my-file.txt");
837
+ const file = Bun.file("s3://my-bucket/my-file.txt");
838
+ ```
839
+
840
+ You can additionally pass `s3` options to the `fetch` and `Bun.file` functions.
841
+
842
+ ```ts s3.ts icon="/icons/typescript.svg" highlight={2-6}
843
+ const response = await fetch("s3://my-bucket/my-file.txt", {
844
+ s3: {
845
+ accessKeyId: "your-access-key",
846
+ secretAccessKey: "your-secret-key",
847
+ endpoint: "https://s3.us-east-1.amazonaws.com",
848
+ },
849
+ headers: {
850
+ range: "bytes=0-1023",
851
+ },
852
+ });
853
+ ```
854
+
855
+ ### UTF-8, UTF-16, and BOM (byte order mark)
856
+
857
+ Like `Response` and `Blob`, `S3File` assumes UTF-8 encoding by default.
858
+
859
+ When calling one of the `text()` or `json()` methods on an `S3File`:
860
+
861
+ - When a UTF-16 byte order mark (BOM) is detected, it will be treated as UTF-16. JavaScriptCore natively supports UTF-16, so it skips the UTF-8 transcoding process (and strips the BOM). This is mostly good, but it does mean if you have invalid surrogate pairs characters in your UTF-16 string, they will be passed through to JavaScriptCore (same as source code).
862
+ - When a UTF-8 BOM is detected, it gets stripped before the string is passed to JavaScriptCore and invalid UTF-8 codepoints are replaced with the Unicode replacement character (`\uFFFD`).
863
+ - UTF-32 is not supported.