Skip to main content

Choosing Your Stack

Choosing the right technology stack is crucial for your ActivityPub implementation. This guide compares popular options and helps you make an informed decision.

Decision Factors​

Consider these factors when choosing your stack:

FactorQuestions to Ask
Team expertiseWhat languages does your team know?
Performance needsHow many users/requests do you expect?
EcosystemAre there existing ActivityPub libraries?
HostingWhere will you deploy?
Time constraintsDo you need to ship quickly?

Language Comparison​

JavaScript/TypeScript​

Pros:

  • Large ecosystem and community
  • Easy to get started
  • Good ActivityPub library support
  • Runs everywhere (Node.js, Deno, Bun)

Cons:

  • Single-threaded (need clustering for CPU-bound tasks)
  • Memory usage can be high

Best for: Quick prototypes, web-focused teams, full-stack development

Popular libraries:

// Example with Fedify
import { createFederation, MemoryKvStore, Person } from "@fedify/fedify";

const federation = createFederation({ kv: new MemoryKvStore() });

federation.setActorDispatcher("/users/{identifier}", (ctx, identifier) => {
return new Person({
id: ctx.getActorUri(identifier),
preferredUsername: identifier,
});
});

Python​

Pros:

  • Clean, readable syntax
  • Great for data processing
  • Strong crypto libraries
  • Good for AI/ML integration

Cons:

  • Slower than compiled languages
  • GIL limits parallelism

Best for: Backend services, data-heavy applications, ML integration

Popular libraries:

# Example with Flask
from flask import Flask, request, jsonify
import json

app = Flask(__name__)

@app.route('/users/<username>/inbox', methods=['POST'])
def inbox(username):
activity = request.get_json()
# Process activity
return '', 202

@app.route('/users/<username>', methods=['GET'])
def actor(username):
return jsonify({
'@context': 'https://www.w3.org/ns/activitystreams',
'type': 'Person',
'id': f'https://example.com/users/{username}',
# ... more properties
})

Go​

Pros:

  • Excellent performance
  • Great concurrency model
  • Single binary deployment
  • Strong standard library

Cons:

  • Steeper learning curve
  • Less flexible than dynamic languages
  • Smaller ActivityPub ecosystem

Best for: High-performance servers, microservices, scale

Popular libraries:

// Example with go-fed
package main

import (
"github.com/go-fed/activity/pub"
"github.com/go-fed/activity/streams"
)

func main() {
actor := streams.NewActivityStreamsPerson()
// Configure actor...

handler := pub.NewSocialActor(
db,
clock,
NewSocialProtocol(),
)
// Set up HTTP handlers...
}

Rust​

Pros:

  • Maximum performance
  • Memory safety
  • Great for long-running services
  • Growing ecosystem

Cons:

  • Steep learning curve
  • Longer development time
  • Smaller ActivityPub ecosystem

Best for: Performance-critical applications, infrastructure

Popular libraries:

// Example with activitypub-federation
use activitypub_federation::{
config::FederationConfig,
traits::Actor,
};

#[derive(Clone)]
struct MyActor {
id: Url,
// ...
}

impl Actor for MyActor {
fn id(&self) -> Url {
self.id.clone()
}
// ... implement other methods
}

Ruby​

Pros:

  • Developer-friendly
  • Rails ecosystem
  • Mastodon uses it

Cons:

  • Performance limitations
  • Smaller ActivityPub library support

Best for: Rails teams, Mastodon forks

Popular libraries:

# Example with Rails
class InboxController < ApplicationController
def create
activity = JSON.parse(request.body.read)
ProcessActivityJob.perform_later(activity)
head :accepted
end
end

PHP​

Pros:

  • Wide hosting availability
  • Large community
  • Easy deployment

Cons:

  • Performance limitations
  • Fewer ActivityPub libraries

Best for: WordPress integration, shared hosting

Popular libraries:

Framework Recommendations​

By Use Case​

Use CaseRecommended Stack
MicrobloggingRuby/Rails, Go
Photo sharingPHP (Pixelfed), Node.js
Link aggregationRust (Lemmy), Go
Video hostingPython, Go
Lightweight serverGo, Rust
Quick prototypeNode.js, Python

By Scale​

ScaleRecommended Approach
< 100 usersAny language, single server
100-1000 usersNode.js/Python with caching
1000-10000 usersGo/Rust, Redis, queue workers
10000+ usersDistributed architecture, Go/Rust

Dedicated ActivityPub Frameworks​

These frameworks provide most ActivityPub functionality out of the box:

Fedify (TypeScript)​

Modern, type-safe ActivityPub framework:

import { createFederation } from "@fedify/fedify";

const federation = createFederation<Context>({
kv: new MemoryKvStore(),
});

federation.setActorDispatcher("/users/{handle}", async (ctx, handle) => {
return new Person({
id: ctx.getActorUri(handle),
name: handle,
// ...
});
});

Best for: TypeScript projects, modern development

go-fed/activity (Go)​

Complete ActivityPub implementation:

handler := pub.NewSocialActor(
database,
clock,
protocol,
)

Best for: Go projects needing full spec compliance

activitypub-federation (Rust)​

Battle-tested library from Lemmy:

let config = FederationConfig::builder()
.app_data(data)
.build()?;

Best for: Rust projects, high-performance needs

Build vs. Use Existing​

Start from Scratch​

When to do it:

  • Learning purposes
  • Unique requirements
  • Full control needed

Effort: High (months of work)

Fork Existing Software​

When to do it:

  • Similar feature set needed
  • Community and maintenance matters
  • Faster time to market

Popular bases:

  • Mastodon (Ruby) - Microblogging
  • GoToSocial (Go) - Lightweight microblogging
  • Pixelfed (PHP) - Photo sharing
  • Lemmy (Rust) - Link aggregation

Use a Framework​

When to do it:

  • Need flexibility
  • Different use case than existing software
  • Want to focus on features, not protocol

Options:

  • Fedify (TypeScript)
  • go-fed (Go)
  • activitypub-federation (Rust)

Database Considerations​

PostgreSQL​

Most common choice. Used by Mastodon, Pixelfed, Lemmy.

Pros: Reliable, feature-rich, good JSON support Cons: Resource-intensive

SQLite​

Good for small instances. Used by GoToSocial.

Pros: Simple, no server needed, portable Cons: Concurrent write limitations

MongoDB​

Document-oriented, matches ActivityPub's JSON structure.

Pros: Flexible schema, good for activities Cons: Different paradigm, operational complexity

Deployment Considerations​

Traditional VPS​

  • Full control
  • Predictable costs
  • Manual scaling

Good for: Most small-medium instances

Container-Based (Docker/K8s)​

  • Easy deployment
  • Scaling options
  • Complex for small teams

Good for: Teams with container experience

Serverless​

  • Auto-scaling
  • Pay per use
  • Cold start issues

Good for: Variable traffic, cost optimization

caution

Serverless can be tricky for ActivityPub due to long-running inbox processing and WebSocket needs.

Making Your Decision​

Quick Start (Learning)​

Language: JavaScript/TypeScript
Framework: Fedify (Node.js, Deno, or Bun)
Database: SQLite
Deploy: Local or single VPS

Production-Ready (Small)​

Language: Go or TypeScript
Framework: Fedify or GoToSocial-based
Database: PostgreSQL
Deploy: VPS with Docker

Scale-Ready​

Language: Go or Rust
Framework: Custom or Lemmy-based
Database: PostgreSQL + Redis
Deploy: Kubernetes or similar

Next Steps​

Based on your choice:

  1. Building an Actor - Start implementing
  2. Libraries Overview - Explore available tools
  3. JavaScript Libraries - JS-specific options
  4. Go Libraries - Go-specific options