Skip to content

Build for the fediverse,
skip the boilerplate.

Fedify is a TypeScript framework that handles federation, signatures, discovery, activity vocabulary, and delivery behind type-safe APIs, so you ship features, not specs. It's modular, too: adopt the whole thing or just the parts you need, and it never dictates how your app is built.

npm install @fedify/fedify
Runs onNode.jsDenoBunCloudflare Workers

What's Fedify?

A federation framework, not just a protocol library.

The fediverse is millions of accounts spread across thousands of independent servers, all talking through shared protocols. Implementing those protocols by hand is a lot of subtle, security-critical work. Fedify handles all of it, actors and activity vocabulary, signatures, discovery, and queued delivery, so a post on your server reaches Mastodon, Misskey, Lemmy, and the rest, correctly and securely. It's that broad, yet modular: take only the pieces you need, and it won't decide how the rest of your app is structured.

Read the full introduction →

Why Fedify?

Federation is a stack of specs. Fedify implements it.

Going federated means getting a whole pile of standards right, and keeping them right as they evolve. Fedify implements them so you don't have to, and exposes them through one coherent, typed API.

Work across servers
Fedify negotiates HTTP signature formats and handles discovery through WebFinger and NodeInfo.
Build on trust and consent
Check object origins and integrity proofs, and use interaction helpers in your app to request and verify consent for quotes and recommendations.
Keep identity across gateways
Portable object IDs contain a DID instead of a host. Their integrity proofs can be verified without trusting the hosting gateway.
See the full rationale →

Looks like this

Define an actor. Fedify handles the wire.

Map a route to a typed actor and you get a working, discoverable, cryptographically-signed ActivityPub endpoint, no manual JSON-LD, no signature plumbing.

Follow the tutorial →
import { createFederation, Person } from "@fedify/fedify";

const federation = createFederation({ kv });

federation.setActorDispatcher(
  "/users/{identifier}",
  async (ctx, identifier) => {
    const user = await db.getUser(identifier);
    if (user == null) return null;
    return new Person({
      id: ctx.getActorUri(identifier),
      preferredUsername: identifier,
      name: user.name,
      inbox: ctx.getInboxUri(identifier),
    });
  },
);

Type-safe vocabulary

Type-safe objects, no JSON-LD headaches

Fedify models the whole Activity Vocabulary as immutable, type-safe objects, backed by a real JSON-LD processor and exposed as a fully typed API.

  • Standard-compliant outputBuild an object and toJsonLd() emits valid, interoperable JSON-LD.
  • One shape to readEvery equivalent JSON-LD form normalizes to the same typed value.
  • References, dereferencedUse getActor() and getObject() to fetch and hydrate remote objects on demand.
  • Secure by defaultAn origin-based security model (FEP-fe34) re-fetches cross-origin embedded objects with IDs. Portable IDs use cryptographic origins derived from their DIDs.
Vocabulary guide →
// In JSON-LD, these four are all equivalent:
"to": "as:Public"
"to": ["as:Public"]
"to": "https://www.w3.org/ns/activitystreams#Public"
"to": ["https://www.w3.org/ns/activitystreams#Public"]

// With the Vocabulary API you read one typed value:
note.toId
// → URL "https://www.w3.org/ns/activitystreams#Public"
const activity = await Activity.fromJsonLd(json);

// Just the URI, no network request:
activity.actorId;
// → URL "https://example.com/users/alice"

// getActor() fetches and hydrates the actor:
const actor = await activity.getActor();
actor?.name;  // "Alice"

Portable objects · FEP-ef61

An identity beyond a single server

Give actors and posts IDs based on a decentralized identifier (DID), independent of any server's domain. Fedify can serve these objects through gateways, sign and deliver their activities, and verify portable objects from other servers.

Object Integrity Proofs authenticate the objects themselves, wherever they are hosted. Your application manages storage and synchronization between gateways.

Portable objects guide →

Reliable at scale

Reliable delivery, even to huge audiences

Outgoing activities go through a message queue, so a flaky recipient never costs you a post. For large audiences, a two-stage fan-out returns instantly and delivers to every inbox in the background.

Queued and retried

Outgoing activities go through a queue and retry with exponential backoff, so a flaky server never costs you a post.

Fan-out for scale

A two-stage fan-out returns instantly and delivers to thousands of inboxes in the background, each retried on its own.

Pluggable brokers

Run the queue on the backend you already operate, and swap it later without touching your application code.

Run the queue on the broker you prefer

  • and more

On Netlify Functions, Fedify processes queued deliveries through Async Workloads events, without a long-running queue worker.

Background tasks

Run your app's jobs in the background

Send digest emails, rebuild timelines, or fetch link previews using the same queue infrastructure that delivers your activities. Define a task once, then enqueue it from any federation context.

  • Typed and validateda Standard Schema, such as one from Zod or Valibot, checks payloads at enqueue time and again on the worker.
  • Delays and retriespostpone jobs and retry failed ones under a configurable policy.
  • Your existing queuereuse the outbox queue, or give tasks a queue and worker of their own.
Background tasks guide →
import { z } from "zod";

const sendDigest = federation.defineTask("sendDigest", {
  schema: z.object({
    userId: z.string(),
    since: z.date(),
  }),
  handler: async (_ctx, data) => {
    await sendDigestEmail(data.userId, data.since);
  },
});

await ctx.enqueueTask(sendDigest, {
  userId: "alice",
  since: new Date(),
}, { delay: { minutes: 30 } });

Interaction controls

Build interactions around consent

Use @fedify/interaction-controls for likes, replies, boosts, quotes, and featuring actors in recommendation collections. Typed helpers evaluate policies and create and verify interaction requests and authorizations.

The helpers support GoToSocial interaction controls, FEP-044f quote authorization, and FEP-7aa9 featured recommendation collections. Your application handles delivery, storage, and moderation.

Interaction controls guide →
evaluatePolicy()
automatic
Eligible for automatic approval.
manual
Needs the owner's approval.
denied
Not allowed by the policy.

Works with your stack

Drops into the web framework you already use

Fedify doesn't take over your app. It runs as middleware on the domain and port you already have, using content negotiation to pick out federation traffic and leaving the rest of your routes alone. First-party packages cover the frameworks below. Scaffold a project with fedify init. For AdonisJS, add Fedify to an existing app on Node.js with node ace add @fedify/adonisjs.

  • and more

No official package? No problem.

Fedify is built on the web-standard Request and Response, so dropping it into anything with middleware takes about a dozen lines.

Custom middleware guide →
import { federation } from "./federation.ts";

export default (request: Request, next) =>
  federation.fetch(request, {
    contextData: undefined,
    onNotFound: next,        // not a federation request
    onNotAcceptable: next,   // fall back to your HTML
  });

Your data, your schema

Fedify never owns your data model

Your actors, posts, and followers live in your own database, in whatever schema you already have. Fedify reads them through dispatcher callbacks you write, so the data model stays yours. For its own internal state, a cache and some federation bookkeeping, it relies on a pluggable KvStore: keep it in memory while you develop, or back it with Redis, PostgreSQL, PGlite, MySQL, SQLite, Deno KV, Netlify Blobs, or Cloudflare Workers KV.

Key–value store guide →

Plays well with others

Interoperates with the software people already use

  • and more

Developer tooling

A toolchain for building and debugging

Use the fedify CLI to inspect remote objects and test what your server sends. @fedify/debugger adds a live dashboard of inbox and outbox activity.

@fedify/lint checks actor properties and media upload setup. In ESLint and Oxlint, it can also flag unhandled outbox delivery promises.

Explore the CLI →

Built for production

See exactly what your server is doing

Fedify is instrumented with OpenTelemetry out of the box, so the whole federation lifecycle shows up as traces and metrics in the observability stack you already run.

  • Distributed tracesEvery step is a span: HTTP, inbox, outbox, fan-out, signatures, and WebFinger.
  • Rich metricsCounters and histograms for delivery, queue depth, signature verification, and more.
  • Any OTLP backendShip to Grafana, Jaeger, Sentry, or Deno's built-in OpenTelemetry.
  • Structured logs tooTraceable JSON logging via LogTape, correlated by request and message IDs.
  • Inbox request reportsInspect signature and proof checks, keys used, authentication decisions, and request outcomes for accepted and rejected deliveries with onRequestFinished(), independently of trace sampling.
OpenTelemetry guide →

ActivityPub API

Accept posts straight from your clients

The ActivityPub API, the client-to-server (C2S) side of the protocol, is something of a holy grail in the fediverse, and Fedify is ready for it. Route POST requests to an actor's outbox through typed listeners and authorize them however you like.

  • Typed outbox listenershandle client posts per activity type, exactly like inbox listeners.
  • Auth your wayan authorize() hook plugs in OAuth, access tokens, or sessions.
  • Standard, not bespokeclients speak the real ActivityPub outbox, so there's no custom API to maintain.
Outbox listeners guide →
federation
  .setOutboxListeners("/users/{identifier}/outbox")
  .on(Create, async (ctx, activity) => {
    await saveAndDeliver(ctx, activity);
  })
  .authorize(async (ctx, id) =>
    (await getSession(ctx.request))?.user === id);

The people behind Fedify

An open source project, built and maintained by people in the fediverse.

  • Hong Minhee 洪民憙

    Contributing since 2024

  • Jiwon Kwon 權祉源

    Contributing since 2025

  • ChanHaeng Lee 李璨行

    Contributing since 2025

Meet the team and contributors

Ready to join the fediverse?

Install Fedify and have a federated actor running in minutes.

Need a hand? Ask the community on GitHub Discussions or Matrix, or tag #Fedify in the fediverse.

Fedify is free and open source. Meet our sponsors →

Also from the Fedify team:BotKitDrFed

Backed by an investment from