diff --git a/examples/README.md b/examples/README.md
index 633978c87..531a24bd3 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -52,6 +52,7 @@
### Data loaders
+- [`loader-airtable`](https://observablehq.observablehq.cloud/framework-example-loader-airtable/) - Loading data from Airtable
- [`loader-arrow`](https://observablehq.observablehq.cloud/framework-example-loader-arrow/) - Generating Apache Arrow IPC files
- [`loader-databricks`](https://observablehq.observablehq.cloud/framework-example-loader-databricks/) - Loading data from Databricks
- [`loader-duckdb`](https://observablehq.observablehq.cloud/framework-example-loader-duckdb/) - Processing data with DuckDB
diff --git a/examples/loader-airtable/README.md b/examples/loader-airtable/README.md
new file mode 100644
index 000000000..27af460c8
--- /dev/null
+++ b/examples/loader-airtable/README.md
@@ -0,0 +1,7 @@
+[Framework examples →](../)
+
+# Airtable data loader
+
+View live:
+
+This Observable Framework example demonstrates how to write a JavaScript data loader that uses [Airtable](https://airtable.com/) as a backend. The data loader lives in [`src/data/penguins.csv.ts`](./src/data/penguins.csv.ts).
diff --git a/examples/loader-airtable/observablehq.config.js b/examples/loader-airtable/observablehq.config.js
new file mode 100644
index 000000000..fb0f92431
--- /dev/null
+++ b/examples/loader-airtable/observablehq.config.js
@@ -0,0 +1,3 @@
+export default {
+ root: "src"
+};
diff --git a/examples/loader-airtable/package.json b/examples/loader-airtable/package.json
new file mode 100644
index 000000000..ef86e357e
--- /dev/null
+++ b/examples/loader-airtable/package.json
@@ -0,0 +1,22 @@
+{
+ "type": "module",
+ "private": true,
+ "scripts": {
+ "clean": "rimraf src/.observablehq/cache",
+ "build": "rimraf dist && observable build",
+ "dev": "observable preview",
+ "deploy": "observable deploy",
+ "observable": "observable"
+ },
+ "dependencies": {
+ "@observablehq/framework": "^1.7.0",
+ "airtable": "^0.12.2",
+ "dotenv": "^16.4.5"
+ },
+ "devDependencies": {
+ "rimraf": "^5.0.5"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+}
diff --git a/examples/loader-airtable/src/.gitignore b/examples/loader-airtable/src/.gitignore
new file mode 100644
index 000000000..1235d15eb
--- /dev/null
+++ b/examples/loader-airtable/src/.gitignore
@@ -0,0 +1 @@
+/.observablehq/cache/
diff --git a/examples/loader-airtable/src/data/penguins.csv b/examples/loader-airtable/src/data/penguins.csv
new file mode 100644
index 000000000..a1c6de8d4
--- /dev/null
+++ b/examples/loader-airtable/src/data/penguins.csv
@@ -0,0 +1,345 @@
+sex,body_mass_g,culmen_length_mm,culmen_depth_mm,id,flipper_length_mm,island,species
+MALE,3750,39.1,18.7,1,181,Torgersen,Adelie
+FEMALE,3800,39.5,17.4,2,186,Torgersen,Adelie
+FEMALE,3250,40.3,18,3,195,Torgersen,Adelie
+,,,,4,,Torgersen,Adelie
+FEMALE,3450,36.7,19.3,5,193,Torgersen,Adelie
+MALE,3650,39.3,20.6,6,190,Torgersen,Adelie
+FEMALE,3625,38.9,17.8,7,181,Torgersen,Adelie
+MALE,4675,39.2,19.6,8,195,Torgersen,Adelie
+,3475,34.1,18.1,9,193,Torgersen,Adelie
+,4250,42,20.2,10,190,Torgersen,Adelie
+,3300,37.8,17.1,11,186,Torgersen,Adelie
+,3700,37.8,17.3,12,180,Torgersen,Adelie
+FEMALE,3200,41.1,17.6,13,182,Torgersen,Adelie
+MALE,3800,38.6,21.2,14,191,Torgersen,Adelie
+MALE,4400,34.6,21.1,15,198,Torgersen,Adelie
+FEMALE,3700,36.6,17.8,16,185,Torgersen,Adelie
+FEMALE,3450,38.7,19,17,195,Torgersen,Adelie
+MALE,4500,42.5,20.7,18,197,Torgersen,Adelie
+FEMALE,3325,34.4,18.4,19,184,Torgersen,Adelie
+MALE,4200,46,21.5,20,194,Torgersen,Adelie
+FEMALE,3400,37.8,18.3,21,174,Biscoe,Adelie
+MALE,3600,37.7,18.7,22,180,Biscoe,Adelie
+FEMALE,3800,35.9,19.2,23,189,Biscoe,Adelie
+MALE,3950,38.2,18.1,24,185,Biscoe,Adelie
+MALE,3800,38.8,17.2,25,180,Biscoe,Adelie
+FEMALE,3800,35.3,18.9,26,187,Biscoe,Adelie
+MALE,3550,40.6,18.6,27,183,Biscoe,Adelie
+FEMALE,3200,40.5,17.9,28,187,Biscoe,Adelie
+FEMALE,3150,37.9,18.6,29,172,Biscoe,Adelie
+MALE,3950,40.5,18.9,30,180,Biscoe,Adelie
+FEMALE,3250,39.5,16.7,31,178,Dream,Adelie
+MALE,3900,37.2,18.1,32,178,Dream,Adelie
+FEMALE,3300,39.5,17.8,33,188,Dream,Adelie
+MALE,3900,40.9,18.9,34,184,Dream,Adelie
+FEMALE,3325,36.4,17,35,195,Dream,Adelie
+MALE,4150,39.2,21.1,36,196,Dream,Adelie
+MALE,3950,38.8,20,37,190,Dream,Adelie
+FEMALE,3550,42.2,18.5,38,180,Dream,Adelie
+FEMALE,3300,37.6,19.3,39,181,Dream,Adelie
+MALE,4650,39.8,19.1,40,184,Dream,Adelie
+FEMALE,3150,36.5,18,41,182,Dream,Adelie
+MALE,3900,40.8,18.4,42,195,Dream,Adelie
+FEMALE,3100,36,18.5,43,186,Dream,Adelie
+MALE,4400,44.1,19.7,44,196,Dream,Adelie
+FEMALE,3000,37,16.9,45,185,Dream,Adelie
+MALE,4600,39.6,18.8,46,190,Dream,Adelie
+MALE,3425,41.1,19,47,182,Dream,Adelie
+,2975,37.5,18.9,48,179,Dream,Adelie
+FEMALE,3450,36,17.9,49,190,Dream,Adelie
+MALE,4150,42.3,21.2,50,191,Dream,Adelie
+FEMALE,3500,39.6,17.7,51,186,Biscoe,Adelie
+MALE,4300,40.1,18.9,52,188,Biscoe,Adelie
+FEMALE,3450,35,17.9,53,190,Biscoe,Adelie
+MALE,4050,42,19.5,54,200,Biscoe,Adelie
+FEMALE,2900,34.5,18.1,55,187,Biscoe,Adelie
+MALE,3700,41.4,18.6,56,191,Biscoe,Adelie
+FEMALE,3550,39,17.5,57,186,Biscoe,Adelie
+MALE,3800,40.6,18.8,58,193,Biscoe,Adelie
+FEMALE,2850,36.5,16.6,59,181,Biscoe,Adelie
+MALE,3750,37.6,19.1,60,194,Biscoe,Adelie
+FEMALE,3150,35.7,16.9,61,185,Biscoe,Adelie
+MALE,4400,41.3,21.1,62,195,Biscoe,Adelie
+FEMALE,3600,37.6,17,63,185,Biscoe,Adelie
+MALE,4050,41.1,18.2,64,192,Biscoe,Adelie
+FEMALE,2850,36.4,17.1,65,184,Biscoe,Adelie
+MALE,3950,41.6,18,66,192,Biscoe,Adelie
+FEMALE,3350,35.5,16.2,67,195,Biscoe,Adelie
+MALE,4100,41.1,19.1,68,188,Biscoe,Adelie
+FEMALE,3050,35.9,16.6,69,190,Torgersen,Adelie
+MALE,4450,41.8,19.4,70,198,Torgersen,Adelie
+FEMALE,3600,33.5,19,71,190,Torgersen,Adelie
+MALE,3900,39.7,18.4,72,190,Torgersen,Adelie
+FEMALE,3550,39.6,17.2,73,196,Torgersen,Adelie
+MALE,4150,45.8,18.9,74,197,Torgersen,Adelie
+FEMALE,3700,35.5,17.5,75,190,Torgersen,Adelie
+MALE,4250,42.8,18.5,76,195,Torgersen,Adelie
+FEMALE,3700,40.9,16.8,77,191,Torgersen,Adelie
+MALE,3900,37.2,19.4,78,184,Torgersen,Adelie
+FEMALE,3550,36.2,16.1,79,187,Torgersen,Adelie
+MALE,4000,42.1,19.1,80,195,Torgersen,Adelie
+FEMALE,3200,34.6,17.2,81,189,Torgersen,Adelie
+MALE,4700,42.9,17.6,82,196,Torgersen,Adelie
+FEMALE,3800,36.7,18.8,83,187,Torgersen,Adelie
+MALE,4200,35.1,19.4,84,193,Torgersen,Adelie
+FEMALE,3350,37.3,17.8,85,191,Dream,Adelie
+MALE,3550,41.3,20.3,86,194,Dream,Adelie
+MALE,3800,36.3,19.5,87,190,Dream,Adelie
+FEMALE,3500,36.9,18.6,88,189,Dream,Adelie
+MALE,3950,38.3,19.2,89,189,Dream,Adelie
+FEMALE,3600,38.9,18.8,90,190,Dream,Adelie
+FEMALE,3550,35.7,18,91,202,Dream,Adelie
+MALE,4300,41.1,18.1,92,205,Dream,Adelie
+FEMALE,3400,34,17.1,93,185,Dream,Adelie
+MALE,4450,39.6,18.1,94,186,Dream,Adelie
+FEMALE,3300,36.2,17.3,95,187,Dream,Adelie
+MALE,4300,40.8,18.9,96,208,Dream,Adelie
+FEMALE,3700,38.1,18.6,97,190,Dream,Adelie
+MALE,4350,40.3,18.5,98,196,Dream,Adelie
+FEMALE,2900,33.1,16.1,99,178,Dream,Adelie
+MALE,4100,43.2,18.5,100,192,Dream,Adelie
+FEMALE,3725,35,17.9,101,192,Biscoe,Adelie
+MALE,4725,41,20,102,203,Biscoe,Adelie
+FEMALE,3075,37.7,16,103,183,Biscoe,Adelie
+MALE,4250,37.8,20,104,190,Biscoe,Adelie
+FEMALE,2925,37.9,18.6,105,193,Biscoe,Adelie
+MALE,3550,39.7,18.9,106,184,Biscoe,Adelie
+FEMALE,3750,38.6,17.2,107,199,Biscoe,Adelie
+MALE,3900,38.2,20,108,190,Biscoe,Adelie
+FEMALE,3175,38.1,17,109,181,Biscoe,Adelie
+MALE,4775,43.2,19,110,197,Biscoe,Adelie
+FEMALE,3825,38.1,16.5,111,198,Biscoe,Adelie
+MALE,4600,45.6,20.3,112,191,Biscoe,Adelie
+FEMALE,3200,39.7,17.7,113,193,Biscoe,Adelie
+MALE,4275,42.2,19.5,114,197,Biscoe,Adelie
+FEMALE,3900,39.6,20.7,115,191,Biscoe,Adelie
+MALE,4075,42.7,18.3,116,196,Biscoe,Adelie
+FEMALE,2900,38.6,17,117,188,Torgersen,Adelie
+MALE,3775,37.3,20.5,118,199,Torgersen,Adelie
+FEMALE,3350,35.7,17,119,189,Torgersen,Adelie
+MALE,3325,41.1,18.6,120,189,Torgersen,Adelie
+FEMALE,3150,36.2,17.2,121,187,Torgersen,Adelie
+MALE,3500,37.7,19.8,122,198,Torgersen,Adelie
+FEMALE,3450,40.2,17,123,176,Torgersen,Adelie
+MALE,3875,41.4,18.5,124,202,Torgersen,Adelie
+FEMALE,3050,35.2,15.9,125,186,Torgersen,Adelie
+MALE,4000,40.6,19,126,199,Torgersen,Adelie
+FEMALE,3275,38.8,17.6,127,191,Torgersen,Adelie
+MALE,4300,41.5,18.3,128,195,Torgersen,Adelie
+FEMALE,3050,39,17.1,129,191,Torgersen,Adelie
+MALE,4000,44.1,18,130,210,Torgersen,Adelie
+FEMALE,3325,38.5,17.9,131,190,Torgersen,Adelie
+MALE,3500,43.1,19.2,132,197,Torgersen,Adelie
+FEMALE,3500,36.8,18.5,133,193,Dream,Adelie
+MALE,4475,37.5,18.5,134,199,Dream,Adelie
+FEMALE,3425,38.1,17.6,135,187,Dream,Adelie
+MALE,3900,41.1,17.5,136,190,Dream,Adelie
+FEMALE,3175,35.6,17.5,137,191,Dream,Adelie
+MALE,3975,40.2,20.1,138,200,Dream,Adelie
+FEMALE,3400,37,16.5,139,185,Dream,Adelie
+MALE,4250,39.7,17.9,140,193,Dream,Adelie
+FEMALE,3400,40.2,17.1,141,193,Dream,Adelie
+MALE,3475,40.6,17.2,142,187,Dream,Adelie
+FEMALE,3050,32.1,15.5,143,188,Dream,Adelie
+MALE,3725,40.7,17,144,190,Dream,Adelie
+FEMALE,3000,37.3,16.8,145,192,Dream,Adelie
+MALE,3650,39,18.7,146,185,Dream,Adelie
+MALE,4250,39.2,18.6,147,190,Dream,Adelie
+FEMALE,3475,36.6,18.4,148,184,Dream,Adelie
+FEMALE,3450,36,17.8,149,195,Dream,Adelie
+MALE,3750,37.8,18.1,150,193,Dream,Adelie
+FEMALE,3700,36,17.1,151,187,Dream,Adelie
+MALE,4000,41.5,18.5,152,201,Dream,Adelie
+FEMALE,3500,46.5,17.9,153,192,Dream,Chinstrap
+MALE,3900,50,19.5,154,196,Dream,Chinstrap
+MALE,3650,51.3,19.2,155,193,Dream,Chinstrap
+FEMALE,3525,45.4,18.7,156,188,Dream,Chinstrap
+MALE,3725,52.7,19.8,157,197,Dream,Chinstrap
+FEMALE,3950,45.2,17.8,158,198,Dream,Chinstrap
+FEMALE,3250,46.1,18.2,159,178,Dream,Chinstrap
+MALE,3750,51.3,18.2,160,197,Dream,Chinstrap
+FEMALE,4150,46,18.9,161,195,Dream,Chinstrap
+MALE,3700,51.3,19.9,162,198,Dream,Chinstrap
+FEMALE,3800,46.6,17.8,163,193,Dream,Chinstrap
+MALE,3775,51.7,20.3,164,194,Dream,Chinstrap
+FEMALE,3700,47,17.3,165,185,Dream,Chinstrap
+MALE,4050,52,18.1,166,201,Dream,Chinstrap
+FEMALE,3575,45.9,17.1,167,190,Dream,Chinstrap
+MALE,4050,50.5,19.6,168,201,Dream,Chinstrap
+MALE,3300,50.3,20,169,197,Dream,Chinstrap
+FEMALE,3700,58,17.8,170,181,Dream,Chinstrap
+FEMALE,3450,46.4,18.6,171,190,Dream,Chinstrap
+MALE,4400,49.2,18.2,172,195,Dream,Chinstrap
+FEMALE,3600,42.4,17.3,173,181,Dream,Chinstrap
+MALE,3400,48.5,17.5,174,191,Dream,Chinstrap
+FEMALE,2900,43.2,16.6,175,187,Dream,Chinstrap
+MALE,3800,50.6,19.4,176,193,Dream,Chinstrap
+FEMALE,3300,46.7,17.9,177,195,Dream,Chinstrap
+MALE,4150,52,19,178,197,Dream,Chinstrap
+FEMALE,3400,50.5,18.4,179,200,Dream,Chinstrap
+MALE,3800,49.5,19,180,200,Dream,Chinstrap
+FEMALE,3700,46.4,17.8,181,191,Dream,Chinstrap
+MALE,4550,52.8,20,182,205,Dream,Chinstrap
+FEMALE,3200,40.9,16.6,183,187,Dream,Chinstrap
+MALE,4300,54.2,20.8,184,201,Dream,Chinstrap
+FEMALE,3350,42.5,16.7,185,187,Dream,Chinstrap
+MALE,4100,51,18.8,186,203,Dream,Chinstrap
+MALE,3600,49.7,18.6,187,195,Dream,Chinstrap
+FEMALE,3900,47.5,16.8,188,199,Dream,Chinstrap
+FEMALE,3850,47.6,18.3,189,195,Dream,Chinstrap
+MALE,4800,52,20.7,190,210,Dream,Chinstrap
+FEMALE,2700,46.9,16.6,191,192,Dream,Chinstrap
+MALE,4500,53.5,19.9,192,205,Dream,Chinstrap
+MALE,3950,49,19.5,193,210,Dream,Chinstrap
+FEMALE,3650,46.2,17.5,194,187,Dream,Chinstrap
+MALE,3550,50.9,19.1,195,196,Dream,Chinstrap
+FEMALE,3500,45.5,17,196,196,Dream,Chinstrap
+FEMALE,3675,50.9,17.9,197,196,Dream,Chinstrap
+MALE,4450,50.8,18.5,198,201,Dream,Chinstrap
+FEMALE,3400,50.1,17.9,199,190,Dream,Chinstrap
+MALE,4300,49,19.6,200,212,Dream,Chinstrap
+MALE,3250,51.5,18.7,201,187,Dream,Chinstrap
+FEMALE,3675,49.8,17.3,202,198,Dream,Chinstrap
+FEMALE,3325,48.1,16.4,203,199,Dream,Chinstrap
+MALE,3950,51.4,19,204,201,Dream,Chinstrap
+FEMALE,3600,45.7,17.3,205,193,Dream,Chinstrap
+MALE,4050,50.7,19.7,206,203,Dream,Chinstrap
+FEMALE,3350,42.5,17.3,207,187,Dream,Chinstrap
+MALE,3450,52.2,18.8,208,197,Dream,Chinstrap
+FEMALE,3250,45.2,16.6,209,191,Dream,Chinstrap
+MALE,4050,49.3,19.9,210,203,Dream,Chinstrap
+MALE,3800,50.2,18.8,211,202,Dream,Chinstrap
+FEMALE,3525,45.6,19.4,212,194,Dream,Chinstrap
+MALE,3950,51.9,19.5,213,206,Dream,Chinstrap
+FEMALE,3650,46.8,16.5,214,189,Dream,Chinstrap
+FEMALE,3650,45.7,17,215,195,Dream,Chinstrap
+MALE,4000,55.8,19.8,216,207,Dream,Chinstrap
+FEMALE,3400,43.5,18.1,217,202,Dream,Chinstrap
+MALE,3775,49.6,18.2,218,193,Dream,Chinstrap
+MALE,4100,50.8,19,219,210,Dream,Chinstrap
+FEMALE,3775,50.2,18.7,220,198,Dream,Chinstrap
+FEMALE,4500,46.1,13.2,221,211,Biscoe,Gentoo
+MALE,5700,50,16.3,222,230,Biscoe,Gentoo
+FEMALE,4450,48.7,14.1,223,210,Biscoe,Gentoo
+MALE,5700,50,15.2,224,218,Biscoe,Gentoo
+MALE,5400,47.6,14.5,225,215,Biscoe,Gentoo
+FEMALE,4550,46.5,13.5,226,210,Biscoe,Gentoo
+FEMALE,4800,45.4,14.6,227,211,Biscoe,Gentoo
+MALE,5200,46.7,15.3,228,219,Biscoe,Gentoo
+FEMALE,4400,43.3,13.4,229,209,Biscoe,Gentoo
+MALE,5150,46.8,15.4,230,215,Biscoe,Gentoo
+FEMALE,4650,40.9,13.7,231,214,Biscoe,Gentoo
+MALE,5550,49,16.1,232,216,Biscoe,Gentoo
+FEMALE,4650,45.5,13.7,233,214,Biscoe,Gentoo
+MALE,5850,48.4,14.6,234,213,Biscoe,Gentoo
+FEMALE,4200,45.8,14.6,235,210,Biscoe,Gentoo
+MALE,5850,49.3,15.7,236,217,Biscoe,Gentoo
+FEMALE,4150,42,13.5,237,210,Biscoe,Gentoo
+MALE,6300,49.2,15.2,238,221,Biscoe,Gentoo
+FEMALE,4800,46.2,14.5,239,209,Biscoe,Gentoo
+MALE,5350,48.7,15.1,240,222,Biscoe,Gentoo
+MALE,5700,50.2,14.3,241,218,Biscoe,Gentoo
+FEMALE,5000,45.1,14.5,242,215,Biscoe,Gentoo
+FEMALE,4400,46.5,14.5,243,213,Biscoe,Gentoo
+MALE,5050,46.3,15.8,244,215,Biscoe,Gentoo
+FEMALE,5000,42.9,13.1,245,215,Biscoe,Gentoo
+MALE,5100,46.1,15.1,246,215,Biscoe,Gentoo
+,4100,44.5,14.3,247,216,Biscoe,Gentoo
+MALE,5650,47.8,15,248,215,Biscoe,Gentoo
+FEMALE,4600,48.2,14.3,249,210,Biscoe,Gentoo
+MALE,5550,50,15.3,250,220,Biscoe,Gentoo
+MALE,5250,47.3,15.3,251,222,Biscoe,Gentoo
+FEMALE,4700,42.8,14.2,252,209,Biscoe,Gentoo
+FEMALE,5050,45.1,14.5,253,207,Biscoe,Gentoo
+MALE,6050,59.6,17,254,230,Biscoe,Gentoo
+FEMALE,5150,49.1,14.8,255,220,Biscoe,Gentoo
+MALE,5400,48.4,16.3,256,220,Biscoe,Gentoo
+FEMALE,4950,42.6,13.7,257,213,Biscoe,Gentoo
+MALE,5250,44.4,17.3,258,219,Biscoe,Gentoo
+FEMALE,4350,44,13.6,259,208,Biscoe,Gentoo
+MALE,5350,48.7,15.7,260,208,Biscoe,Gentoo
+FEMALE,3950,42.7,13.7,261,208,Biscoe,Gentoo
+MALE,5700,49.6,16,262,225,Biscoe,Gentoo
+FEMALE,4300,45.3,13.7,263,210,Biscoe,Gentoo
+MALE,4750,49.6,15,264,216,Biscoe,Gentoo
+MALE,5550,50.5,15.9,265,222,Biscoe,Gentoo
+FEMALE,4900,43.6,13.9,266,217,Biscoe,Gentoo
+FEMALE,4200,45.5,13.9,267,210,Biscoe,Gentoo
+MALE,5400,50.5,15.9,268,225,Biscoe,Gentoo
+FEMALE,5100,44.9,13.3,269,213,Biscoe,Gentoo
+MALE,5300,45.2,15.8,270,215,Biscoe,Gentoo
+FEMALE,4850,46.6,14.2,271,210,Biscoe,Gentoo
+MALE,5300,48.5,14.1,272,220,Biscoe,Gentoo
+FEMALE,4400,45.1,14.4,273,210,Biscoe,Gentoo
+MALE,5000,50.1,15,274,225,Biscoe,Gentoo
+FEMALE,4900,46.5,14.4,275,217,Biscoe,Gentoo
+MALE,5050,45,15.4,276,220,Biscoe,Gentoo
+FEMALE,4300,43.8,13.9,277,208,Biscoe,Gentoo
+MALE,5000,45.5,15,278,220,Biscoe,Gentoo
+FEMALE,4450,43.2,14.5,279,208,Biscoe,Gentoo
+MALE,5550,50.4,15.3,280,224,Biscoe,Gentoo
+FEMALE,4200,45.3,13.8,281,208,Biscoe,Gentoo
+MALE,5300,46.2,14.9,282,221,Biscoe,Gentoo
+FEMALE,4400,45.7,13.9,283,214,Biscoe,Gentoo
+MALE,5650,54.3,15.7,284,231,Biscoe,Gentoo
+FEMALE,4700,45.8,14.2,285,219,Biscoe,Gentoo
+MALE,5700,49.8,16.8,286,230,Biscoe,Gentoo
+,4650,46.2,14.4,287,214,Biscoe,Gentoo
+MALE,5800,49.5,16.2,288,229,Biscoe,Gentoo
+FEMALE,4700,43.5,14.2,289,220,Biscoe,Gentoo
+MALE,5550,50.7,15,290,223,Biscoe,Gentoo
+FEMALE,4750,47.7,15,291,216,Biscoe,Gentoo
+MALE,5000,46.4,15.6,292,221,Biscoe,Gentoo
+MALE,5100,48.2,15.6,293,221,Biscoe,Gentoo
+FEMALE,5200,46.5,14.8,294,217,Biscoe,Gentoo
+FEMALE,4700,46.4,15,295,216,Biscoe,Gentoo
+MALE,5800,48.6,16,296,230,Biscoe,Gentoo
+FEMALE,4600,47.5,14.2,297,209,Biscoe,Gentoo
+MALE,6000,51.1,16.3,298,220,Biscoe,Gentoo
+FEMALE,4750,45.2,13.8,299,215,Biscoe,Gentoo
+MALE,5950,45.2,16.4,300,223,Biscoe,Gentoo
+FEMALE,4625,49.1,14.5,301,212,Biscoe,Gentoo
+MALE,5450,52.5,15.6,302,221,Biscoe,Gentoo
+FEMALE,4725,47.4,14.6,303,212,Biscoe,Gentoo
+MALE,5350,50,15.9,304,224,Biscoe,Gentoo
+FEMALE,4750,44.9,13.8,305,212,Biscoe,Gentoo
+MALE,5600,50.8,17.3,306,228,Biscoe,Gentoo
+FEMALE,4600,43.4,14.4,307,218,Biscoe,Gentoo
+MALE,5300,51.3,14.2,308,218,Biscoe,Gentoo
+FEMALE,4875,47.5,14,309,212,Biscoe,Gentoo
+MALE,5550,52.1,17,310,230,Biscoe,Gentoo
+FEMALE,4950,47.5,15,311,218,Biscoe,Gentoo
+MALE,5400,52.2,17.1,312,228,Biscoe,Gentoo
+FEMALE,4750,45.5,14.5,313,212,Biscoe,Gentoo
+MALE,5650,49.5,16.1,314,224,Biscoe,Gentoo
+FEMALE,4850,44.5,14.7,315,214,Biscoe,Gentoo
+MALE,5200,50.8,15.7,316,226,Biscoe,Gentoo
+MALE,4925,49.4,15.8,317,216,Biscoe,Gentoo
+FEMALE,4875,46.9,14.6,318,222,Biscoe,Gentoo
+FEMALE,4625,48.4,14.4,319,203,Biscoe,Gentoo
+MALE,5250,51.1,16.5,320,225,Biscoe,Gentoo
+FEMALE,4850,48.5,15,321,219,Biscoe,Gentoo
+MALE,5600,55.9,17,322,228,Biscoe,Gentoo
+FEMALE,4975,47.2,15.5,323,215,Biscoe,Gentoo
+MALE,5500,49.1,15,324,228,Biscoe,Gentoo
+,4725,47.3,13.8,325,216,Biscoe,Gentoo
+MALE,5500,46.8,16.1,326,215,Biscoe,Gentoo
+FEMALE,4700,41.7,14.7,327,210,Biscoe,Gentoo
+MALE,5500,53.4,15.8,328,219,Biscoe,Gentoo
+FEMALE,4575,43.3,14,329,208,Biscoe,Gentoo
+MALE,5500,48.1,15.1,330,209,Biscoe,Gentoo
+FEMALE,5000,50.5,15.2,331,216,Biscoe,Gentoo
+MALE,5950,49.8,15.9,332,229,Biscoe,Gentoo
+FEMALE,4650,43.5,15.2,333,213,Biscoe,Gentoo
+MALE,5500,51.5,16.3,334,230,Biscoe,Gentoo
+FEMALE,4375,46.2,14.1,335,217,Biscoe,Gentoo
+MALE,5850,55.1,16,336,230,Biscoe,Gentoo
+,4875,44.5,15.7,337,217,Biscoe,Gentoo
+MALE,6000,48.8,16.2,338,222,Biscoe,Gentoo
+FEMALE,4925,47.2,13.7,339,214,Biscoe,Gentoo
+,,,,340,,Biscoe,Gentoo
+FEMALE,4850,46.8,14.3,341,215,Biscoe,Gentoo
+MALE,5750,50.4,15.7,342,222,Biscoe,Gentoo
+FEMALE,5200,45.2,14.8,343,212,Biscoe,Gentoo
+MALE,5400,49.9,16.1,344,213,Biscoe,Gentoo
\ No newline at end of file
diff --git a/examples/loader-airtable/src/data/penguins.csv.ts b/examples/loader-airtable/src/data/penguins.csv.ts
new file mode 100644
index 000000000..852c74a99
--- /dev/null
+++ b/examples/loader-airtable/src/data/penguins.csv.ts
@@ -0,0 +1,24 @@
+import "dotenv/config";
+import Airtable from "airtable";
+import {csvFormat} from "d3-dsv";
+
+const {AIRTABLE_PAT, AIRTABLE_DB} = process.env;
+
+Airtable.configure({apiKey: AIRTABLE_PAT});
+
+const base = Airtable.base(AIRTABLE_DB as string);
+
+const data: any[] = [];
+
+base("penguins")
+ .select({view: "Grid view"})
+ .eachPage(
+ (records, fetchNextPage) => {
+ records.forEach((record) => data.push(record.fields));
+ fetchNextPage();
+ },
+ (err) => {
+ if (err) throw err;
+ process.stdout.write(csvFormat(data));
+ }
+ );
diff --git a/examples/loader-airtable/src/index.md b/examples/loader-airtable/src/index.md
new file mode 100644
index 000000000..9dceda4e7
--- /dev/null
+++ b/examples/loader-airtable/src/index.md
@@ -0,0 +1,63 @@
+# Airtable data loader
+
+Here’s a TypeScript data loader that reads values from a database hosted on [Airtable](https://airtable.com/).
+
+It uses the [airtable.js](https://github.com/Airtable/airtable.js) development kit. See [the official API documentation](https://airtable.com/developers/web/api/introduction), which allows you to select your database for “live documentation” running on your own data; make sure to select the “JavaScript” tab.
+
+To run this data loader, you’ll need to create a personal access token at [/create/tokens](https://airtable.com/create/tokens) and save its value in the `.env` file at the root of the project. (Mine is scoped to only _read_ values from the _penguins_ database.) In that same `.env` file, you will also specify the database id:
+
+```txt
+AIRTABLE_PAT="patXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXX"
+AIRTABLE_DB="appWXXXXXXXXX"
+```
+
+
+
+To run this data loader, you’ll need to install `airtable` and `dotenv` using your preferred package manager such as npm or Yarn.
+
+
+
+The data loader’s code:
+
+```js run=false
+import "dotenv/config";
+import Airtable from "airtable";
+import {csvFormat} from "d3-dsv";
+
+const {AIRTABLE_PAT, AIRTABLE_DB} = process.env;
+
+Airtable.configure({apiKey: AIRTABLE_PAT});
+
+const base = Airtable.base(AIRTABLE_DB as string);
+
+const data: any[] = [];
+
+base("penguins")
+ .select({view: "Grid view"})
+ .eachPage(
+ (records, fetchNextPage) => {
+ records.forEach((record) => data.push(record.fields));
+ fetchNextPage();
+ },
+ (err) => {
+ if (err) throw err;
+ process.stdout.write(csvFormat(data));
+ }
+ );
+```
+
+It lives in `data/penguins.csv.ts`, so we can load the data using `data/penguins.csv`.
+
+```js
+Inputs.table(penguins)
+```
+
+```js echo
+const penguins = FileAttachment("./data/penguins.csv").csv({typed: true});
+```
+
+
+
+Using the Airtable API you can do more than just read the whole database: it’s also possible to load comments, or make specific queries to get a subset of the values.
+
+