Skip to content

Architecture ​

Differences from upstream ​

Upstream Misskey runs everything in one kind of Node.js process, with Redis and PostgreSQL. misskey-cf splits it into Workers by role and replaces Redis and the job queue with Cloudflare services.

ComponentUpstreammisskey-cf
RuntimeNode.js process5 Workers (split by role)
DatabasePostgreSQLPostgreSQL (same schema, via Hyperdrive)
RedisCaches, timelines, notifications, pub/subNot used (replaced by Durable Objects, KV, and PostgreSQL)
Job queueBullMQCloudflare Queues
Periodic tasksBullMQ repeatable jobsCron Triggers
File storageLocal / S3R2
Image and video processingsharp / ffmpeg (same process)Containers (sharp + ffmpeg)
MailSMTPCloudflare Email Service
Full-text searchMeilisearch and others (optional)Not used (SQL substring match)
Web clientUpstream's Vue clientUpstream's Vue client, built and served as-is

Workers ​

Only the gateway is public. The other Workers are called only through service bindings, Durable Objects, and Queues.

WorkerRole
gatewayThe only public Worker. Serves the web client, generates HTML, and forwards everything else to api
apiEvery API endpoint, ActivityPub in and out, drive, mail, Web Push, job processing, periodic tasks
timelineDelivers posts to followers' timelines and to streaming. Stores notifications
streamPer-user WebSocket connections and online presence
mediaThumbnails and other derivatives, media proxy (sharp / ffmpeg in a Container)

What replaces Redis and the job queue ​

Upstream mechanismmisskey-cf
Caches for meta, roles, and so onPer-execution-environment memory cache and KV
Cache invalidation across processesNone (caches expire)
Streaming event deliverySent directly to a per-user Durable Object
Home, list, and channel timelinesPostgreSQL queries that return the same results
Antenna timelinesDurable Object
Notification storagePer-user Durable Object
Rate limitsDurable Object
RankingsAggregated over the same window in PostgreSQL
ActivityPub delivery and inboxQueues
Webhook deliveryQueues
Account deletion, exports, importsQueues (one step per message)
Poll endings, scheduled notesDurable Object alarms
Relationship processing (follows and so on)Handled within the request (only ActivityPub delivery is asynchronous)
Chart recordingNone (computed from the source data on request)

Main flows ​

Posting ​

The post is saved within the API request, and delivery to followers' timelines happens asynchronously through a Queue.

When there are remote followers, api also enqueues ActivityPub delivery on a separate Queue.

Streaming ​

A WebSocket connection goes from the gateway to api, which authenticates it and hands it to the user's Durable Object (stream). From then on, api and timeline send events to that Durable Object, which forwards them to the socket. While connected, the user's last-active time is refreshed periodically.

ActivityPub ​

Incoming activities from remote servers are enqueued and acknowledged at once; signature verification and processing happen in the Queue consumer. Outgoing deliveries are also enqueued per destination, and failed deliveries are retried with backoff.

Cloudflare services in use ​

ServiceUse
WorkersThe 5 Workers
Static AssetsUpstream's web client
Durable ObjectsTimelines, notifications, WebSockets, online presence, rate limits, timers
QueuesActivityPub in and out, timeline delivery, webhooks, background jobs
HyperdriveConnection to PostgreSQL
R2Drive files
KVCaches for meta and the emoji list
ContainersImage and video processing (sharp + ffmpeg)
Email ServiceMail delivery
Cron TriggersHourly periodic tasks