ep.192『Walking Up the ATProto Stack with Dan Abramov』

  • Theo Steiner
  • Dan Abramov
2026/07/29 に公開107 views

このエピソードについて

@theosteiner.de talked with @danabra.mov about the AT Protocol. Rather than a general overview, they walked up the stack layer by layer — comparing it with HTTP at every step — from AT URIs and records to DIDs, personal data servers, lexicons, and relays.

This is an English episode.

Guest

  • Dan Abramov (@danabra.mov)
    • Previously worked on the React team, then at Bluesky
    • Now works part-time on the Next.js team at Vercel, and plans to relocate to Japan
    • Writes about ATProto on his blog, Overreacted

Walking up the ATProto stack

What ATProto is

  • “AT” officially stands for Authenticated Transfer, but the name also echoes the @ in usernames, because the protocol is fundamentally about identity
  • A good protocol stays invisible. ATProto is a new way to build social apps, originally designed at Bluesky — and originally intended for Twitter itself
  • Today, what you create stays trapped inside the app that hosts it: an answer on Stack Overflow, a comment on GitHub. ATProto lifts that content out into an app-agnostic layer where everything behaves more like files
  • When you post on Bluesky, you are really writing JSON into a folder in the cloud that you control. Anyone can build a competitor with all the existing data already present and interoperable — Blacksky is a real example, with its own moderation policies and no use of the Bluesky API
  • Because every app writes to the same layer, app authors do not need to provide an API. The protocol is the API

Layer 0: what it builds on

  • ATProto does not reinvent the internet. It uses HTTP and WebSockets for transport, CBOR for encoding, DNS for resolution, and public-key cryptography for signatures
  • Where existing primitives fit, it reuses them: domains are used as handles rather than inventing a new naming authority
  • Where they did not fit, it invented: Lexicon, its own JSON type-definition system, chosen over RDF, JSON-LD, and JSON Schema

AT URIs and records

  • An HTTP URI points at a page or a file. Every AT URI points at a record — a piece of JSON with a typed schema. A Bluesky post, a follow, a star on Tangled: all records
  • Each user owns a repo, and records live in the repo of whoever created them. If a million people follow you, that is a million follow records in their repos, not yours. If you follow a million people, those records are yours
  • Records link to each other, which is where AT URIs come in: a comment in your repo links to a post in someone else’s
  • The authority part of an AT URI is not a physical host but the user. That indirection is the whole point — it lets you move your hosting without breaking a single link
  • The friendly form uses your handle, which can change. The canonical form starts with a DID, which never does
  • Dan’s framing: with HTTP the authority is the location; with ATProto the authority is the person. It is closer to RSS and Google Reader — you control the feed, and apps are just clients that read it

Identity: DIDs and the PLC directory

  • A DID is a W3C standard and effectively a meta-standard: did: followed by a method that specifies how to resolve it
  • ATProto supports two methods. did:plc (originally “placeholder”, now “Public Ledger of Credentials”) is centralized and run through a directory; did:web resolves through a normal domain, but if you lose the domain your identity dies with it
  • Either way, resolution yields your DID document — think of it as a passport with three things: where your data is currently hosted, your handle, and your public key
  • The PLC directory is auditable rather than trustless-by-decentralization: fully open source, no private state, replayable from public data, with a queryable history for every DID
  • Each change to a DID document is signed by the key from the previous version, and the first version’s hash is your identifier. So the entire chain of changes to your hosting, keys, and handle can be verified independently

Hosting: the PDS

  • Your records live on a Personal Data Server. One PDS can serve many users, but your own source of truth lives in exactly one place
  • A PDS serves your JSON and offers a WebSocket connection so apps are notified of changes in real time, instead of polling
  • Migration works like changing a Git remote: the repo is copied to the new server, media is moved (still a rough edge — it currently goes server-to-client-to-server), and finally you submit a change to the PLC directory pointing your DID document at the new host
  • Apps barely notice, because AT URIs do not change and most apps have already cached the data
  • Theo migrated his own account from the default Bluesky hosting to eurosky.social
  • PDSls is a good way to see this for yourself: enter a handle and it resolves the DID, resolves the host, and shows the whole repo as collections of JSON

Lexicons

  • Collections are grouped by record type, named in reverse-domain form (app.bsky.feed.like), which gives every app developer a namespace — much like scoped npm packages
  • Records carry a $type field naming their collection, so a record is self-describing even without its URI
  • There are two kinds of links: a weak link is just an AT URI; a strong link adds a CID, the hash of the linked record, so an app can tell whether the target changed since it was referenced
  • Lexicons are the schemas behind these types. Codegen tools turn them into parsers and validators for JavaScript, Swift, Go, and more
  • You do not have to publish a lexicon — but if you do, you publish it as a record. PDSls resolves published types and renders them like documentation
  • You can also reuse other apps’ formats. Three blogging platforms — Leaflet, Offprint, and pckt.blog — converged on a shared lexicon called standard.site, and the Bluesky app now reads it to give those links special treatment with the publication’s brand color
  • Teal FM shows how far this goes: the app has not launched, but the lexicon exists, so people already write listening records and third-party apps already display stats from them
  • Dan’s framing: if you had the world’s JSON, why not run joins across products? Top tracks among the people you follow, trending repos among your friends. Apps become lenses over a shared web of data

Relays and building apps

  • Apps do not hammer every PDS. Relays retransmit a stream of commits and identity events over WebSocket, so an app can subscribe once to everything on the network — or filter down to the collections it cares about
  • The stream carries signed commits, so you do not need to trust the relay. That is the “authenticated” in Authenticated Transfer. Running one is reportedly around $30 a month at current volume
  • If your app defines new record types, no backfill is needed — connect to a relay, filter, and you will see every record from the moment it is created
  • For existing data there are two routes. TAP synchronizes the collections you name and then follows new events. Or use Constellation, a community-run backlink index: given a record, it returns everything that links to it, which is enough to build a working app with no backend at all
  • Because you should shield PDSs from your app’s traffic anyway, load naturally concentrates on the app layer rather than on hosting. Dan’s view is that apps — CDNs, video transcoding — are far more expensive to run than serving JSON
  • Auth collapses too: login uses OAuth, but the OAuth provider is your own PDS. After migrating, Theo’s login screen is eurosky.social
  • Reliability is an early-adopter story. Upstream problems do surface, and the answer is to run your own relay if you need isolation. Dan compares the moment to open source in the 90s

What’s still missing

  • The biggest gap is permissioned data. ATProto deliberately started with public data, because scaling down from public aggregation is easier than scaling up from private
  • Work is underway on a permissioned-data extension for things gated by membership, such as groups. End-to-end encrypted messaging is a separate problem
  • Until then, private and group state has to live in your own database. Roomy Chat, a Discord-like app on ATProto, is one of the projects waiting on this
  • Svelte is notably popular in the ATProto community. Dan’s guess is aesthetic affinity: both feel webby

Where to start

  • Try Bluesky for real, and replace the default Discover feed with the community-run For You feed — findable from the Feeds tab. It learns from your likes, and it runs off someone’s gaming PC at home, which is possible because a feed is just an HTTP service returning an array of AT URIs
  • Starter Packs let you follow everyone in an area of interest with one click

Related links


採用について

使用素材・クレジット

© Presented by UIT