advanced
a type-only model
Importing lexicons.ts pulls the schema library and all your field definitions into the bundle, because validation needs them. To avoid that, use model: record type names only, with the types coming from a pure import type that has no impact on your bundle.
import type lexicons from './lexicons.ts'
import { defineCollection, model } from 'airspace'
const lex = model<typeof lexicons>('dev.roe')
export const notes = defineCollection(lex.note)The trade-off is that nothing is validated on the client, scopesFor cannot see your blob fields, so you will need to add blob:*/* yourself, and singletons will be enforced in types only. The rest of these docs assume validation is on.
workers and other edge runtimes
airspace, airspace/lexicon, airspace/live and the plugins bundle for Cloudflare Workers, Deno and the browser, with no Node built-ins in the graph. Handle lookups import node:dns dynamically, falling back to DNS over HTTPS elsewhere.
airspace/oauth will not bundle: @atproto/oauth-client-node needs node:crypto, node:net and node:dns. Run the OAuth handshake on Node, or use @atproto/oauth-client-browser and pass the resulting session to createAirspace.
bundle size
Minified and gzipped, measured by pnpm size. Lazy chunks load only when spaces, blobs.upload() or passwordSession() are used.
| Import | airspace only | with runtime deps |
|---|---|---|
airspace | 9.2 kB (+5.5 kB lazy) | 36.2 kB (+10.5 kB lazy) |
airspace/lexicon | 3.3 kB | 22.7 kB |
airspace/live | 0.7 kB | 0.7 kB |
airspace/oauth | 0.7 kB | 0.7 kB |
airspace/plugins/markdown | 0.3 kB | 0.3 kB |
airspace/plugins/timestamps | 0.2 kB | 0.2 kB |