diff --git a/README.md b/README.md
index cb6715f1..3617db0b 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,7 @@ For examples, see https://observablehq.com/@observablehq/standard-library.
* [DOM](#dom) - create HTML and SVG elements.
* [Files](#files) - read local files into memory.
+* [FileAttachments](#file_attachments) - read remote files.
* [Generators](#generators) - utilities for generators and iterators.
* [Promises](#promises) - utilities for promises.
* [require](#require) - load third-party libraries.
@@ -273,6 +274,100 @@ A data URL may be significantly less efficient than [URL.createObjectURL](https:
}
```
+### File Attachments
+
+See [File Attachments](https://observablehq.com/@observablehq/file-attachments) on Observable for examples.
+
+#
FileAttachments(resolve) [<>](https://github.com/observablehq/stdlib/blob/master/src/fileAttachment.js "Source")
+
+The **FileAttachments** function exported by the standard library is an abstract class that can be used to fetch files by name from remote URLs. To make it concrete, you call it with a *resolve* function, which is an async function that takes a *name* and returns a URL at which the file of that name may be loaded. For example:
+
+```js
+const FileAttachment = FileAttachments((name) =>
+ `https://my.server/notebooks/demo/${name}`
+);
+```
+
+Or, with a more complex example, calling an API to produce temporary URLs:
+
+```js
+const FileAttachment = FileAttachments(async (name) =>
+ if (cachedUrls.has(name)) return cachedUrls.get(name);
+ const url = await fetchSignedFileUrl(notebookId, name);
+ cachedUrls.set(name, url);
+ return url;
+);
+```
+
+Once you have your **FileAttachment** function defined, you can call it from notebook code:
+
+```js
+photo = FileAttachment("sunset.jpg")
+```
+
+FileAttachments work similarly to the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch), providing methods that return promises to the file’s contents in a handful of convenient forms.
+
+# FileAttachment(name).url() [<>](https://github.com/observablehq/stdlib/blob/master/src/fileAttachment.js "Source")
+
+Returns a promise to the URL at which the file may be retrieved.
+
+```js
+const url = await FileAttachment("file.txt").url();
+```
+
+# FileAttachment(name).text() [<>](https://github.com/observablehq/stdlib/blob/master/src/fileAttachment.js "Source")
+
+Returns a promise to the file’s contents as a JavaScript string.
+
+```js
+const data = d3.csvParse(await FileAttachment("cars.csv").text());
+```
+
+# FileAttachment(name).json() [<>](https://github.com/observablehq/stdlib/blob/master/src/fileAttachment.js "Source")
+
+Returns a promise to the file’s contents, parsed as JSON into JavaScript values.
+
+```js
+const logs = await FileAttachment("weekend-logs.json").json();
+```
+
+# FileAttachment(name).image() [<>](https://github.com/observablehq/stdlib/blob/master/src/fileAttachment.js "Source")
+
+Returns a promise to a file loaded as an [HTML Image](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image). Note that the promise won't resolve until the image has finished loading — making this a useful value to pass to other cells that need to process the image, or paint it into a `