basic infra reqs for different atproto things
running different pieces of atproto #
for how the pieces fit together: atproto for distsys engineers. it frames the firehose as an event log and appviews as precomputed views over it
nothing below needs a specific vendor. i often use fly for small services out of habit — render, railway, or a plain vps on hetzner, digitalocean, or ovh all work, and a vps is usually cheaper if you know what you're doing
glossary
client-side apps. the app is a static bundle. the user signs in with atproto oauth and reads and writes their own PDS. there is no backend to run. doodl stores drawings as PDS blobs. these do not appear in my infra costs. i might use a cloudflare worker for link previews tho. wisp.place hosts the bundle on atproto itself, which is how at-me and punch are served.
microcosm. already indexes the whole network, so a lot of what you'd build a backend for is a http call away. free, no auth, CORS, so the browser can call it directly:
# how many likes does this post have?
curl "https://constellation.microcosm.blue/xrpc/blue.microcosm.links.getBacklinksCount\
?subject=at://did:plc:xbtmt2zjwlrfegqvch7fboei/app.bsky.feed.post/3mn4baqvpoc26\
&source=app.bsky.feed.like:subject.uri"
# {"total":96}
# who is this, and where is their PDS?
curl "https://slingshot.microcosm.blue/xrpc/com.bad-example.identity.resolveMiniDoc\
?identifier=zzstoatzz.io"
# {"did":"did:plc:xbtmt2zjwlrfegqvch7fboei","handle":"zzstoatzz.io",
# "pds":"https://pds.zzstoatzz.io","signing_key":"zQ3shpq..."}
source is just {collection}:{path}, so that works for any lexicon, not only bluesky.
constellation does backlinks (likes, follows,
replies, quotes), slingshot does identity and records,
spacedust streams live interactions, and
ufos shows what lexicons exist. i wrote
protopack to make agents fluent in them.
appviews. an appview consumes the firehose, indexes records, and serves them over xrpc. happyview writes that plumbing for you, so you define lexicons instead of maintaining a firehose consumer.
for storage, start with sqlite on the machine — one file, fast, usually enough. sqlite is not highly available, so if you need more than one instance or you can't lose the disk, use postgres, managed if you'd rather not run it (eg neon, which plyr.fm uses). turso is hosted sqlite with replicas if you want to stay in that world.
appview cost scales with the size of the corpus, not with traffic. that surprised me.
PDS. stock image and a persistent volume. my whole deploy config is three files. blobs live on the volume, so disk is what grows.
relays. a relay subscribes to every PDS in the network, so the traffic allowance decides the machine. check it before you pick a region — hetzner's EU datacenters include 20 TB/mo where their US ones include 3–5 TB.
summary of what, how, where and $ #
figures are what i pay, from a daily snapshot i publish to my PDS as
io.zzstoatzz.cost.snapshot.
| thing | what i run | where | $/mo |
|---|---|---|---|
| client-side app | doodl, at-me, punch | any static host — wisp.place or cloudflare | ~0 |
| appview (framework) | status.zzstoatzz.io | happyview on one small vm | ~6 |
| appview (custom) | typeahead, pub-search, coral | small vm + sqlite, or managed postgres (neon) if you need HA | 5–25 each |
| PDS | pds.zzstoatzz.io — stock bluesky-social/pds image | any vm with a persistent volume (my config) or cirrus | 10.64 |
| relay | relay.waow.tech (go/indigo) and zlay.waow.tech (zig) | hetzner cx53 and cx43 in fsn1, k3s, terraform |
34.99 and 18.49 |
before you deploy an appview, check whether microcosm already answers your question — you deploy nothing and it costs nothing. also i will say that free tier cloudflare is quite generous, pages/workers can take you a long way and go sponsor fig! https://github.com/sponsors/uniphil