WriteFreely

A clean, Markdown-based publishing platform for writers, with built-in ActivityPub federation for connecting to the wider fediverse.

5.3K stars
398 forks
GNU AGPLv3
Go

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
88 /100 Excellent
Development Activity 96
Maintenance 84
Community 72
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
63 /100 Good
Architecture 60
Code Quality 65
Innovation 75
Learning Curve 50

Dependency Health

Score based on the health, technical quality, freshness, and vulnerability profile of runtime dependencies. How we score it →
72 /100 Good
Library Repo Health 61
Library Technical Quality 75
Version Staleness 87
Vulnerabilities 73
Dependency Footprint 70

WriteFreely is a minimalist, open-source blogging platform built in Go, designed around a distraction-free writing experience. Posts are written in Markdown through an auto-saving editor, and the platform strips away comment threads, follower counts, and other typical blog cruft in favor of a plain, readable design. It powers Write.as, the hosted service run by the same team, and has been running in production as one of the earliest ActivityPub-native publishing platforms.

The platform ships as a single static Go binary that works with SQLite out of the box or against MySQL/MariaDB for larger deployments, so self-hosting requires no separate application server. Multi-user instances support per-user blogs, drafts, static “pinned” pages, and hashtag-based categorization, while a single-user mode turns the same binary into a lightweight personal blog.

Federation is a first-class feature: every blog on a WriteFreely instance can be followed from Mastodon, Plume, and other ActivityPub software, and instances can onboard existing users through OAuth 2.0 account linking. Combined with support for 20+ localized languages and RTL scripts, plus Web Monetization payment pointers for tipping, WriteFreely positions itself as a privacy-respecting alternative to centralized blogging platforms like Medium or Substack.

What You Get

  • Distraction-free Markdown editor with auto-save
  • Native ActivityPub federation for follows and replies from Mastodon and other fediverse apps
  • Single static Go binary with a built-in SQLite backend or optional MySQL/MariaDB
  • Multi-user and single-user deployment modes from the same codebase
  • OAuth 2.0 login via Slack, GitLab, Gitea, Write.as, or a generic provider
  • RSS/Atom feeds, sitemaps, webfinger, and nodeinfo endpoints for federation discovery

Common Use Cases

  • Hosting a personal, ad-free blog on your own domain
  • Running a small community or organization’s group blog with multiple contributor accounts
  • Publishing pseudonymous or pen-name writing without linking accounts publicly
  • Standing up a fediverse-connected publishing instance that federates with Mastodon
  • Creating static informational pages (about, contact) by pinning posts to a blog

Under The Hood

Architecture WriteFreely is a monolithic Go web application centered on an App struct (app.go) that directly holds the router (gorilla/mux), datastore, config, key chain, and session store rather than wiring dependencies through a DI container. Routes are registered in routes.go through handler.Web/handler.User middleware wrappers that enforce per-route user levels, while the data layer lives largely in a single large database.go file alongside a hand-rolled SQL dialect abstraction in the db/ package (dialect.go, create.go, alter.go) that generates equivalent DDL for both SQLite and MySQL so the same migrations work across backends. ActivityPub federation is implemented in a substantial activitypub.go that layers directly on top of collection visibility checks (IsPrivate/IsProtected in collections.go), which are threaded consistently through posts.go, feed.go, and activitypub.go — making that visibility abstraction the load-bearing invariant that would ripple across every layer if it changed. Separation of concerns beyond this is achieved mostly through small focused packages (author/, config/, db/, key/, oauth/, page/) rather than internal layering within the core package.

Tech Stack The stack is idiomatic Go with gorilla/mux for routing, gorilla/sessions and gorilla/csrf for session and CSRF handling, and gorilla/schema for form decoding, all backed by database/sql with go-sql-driver/mysql and mattn/go-sqlite3 rather than an ORM. Federation depends on writeas/activity and writeas/httpsig for signed ActivityPub requests plus go-webfinger and go-nodeinfo for discovery, while shared internal libraries from the same maintainers (writeas/web-core, writeas/impart) provide auth helpers, converters, and HTTP error handling. OAuth 2.0 support for Slack, GitLab, Gitea, Write.as, and generic providers is hand-implemented per provider rather than through a single generic OAuth2 client library. The project builds and ships as a static binary via a Makefile, with Dockerfile/Dockerfile.prod and docker-compose for containerized deployment.

Code Quality The repo includes a reasonable spread of test files (database_test.go, oauth_test.go, posts_test.go, signup_test.go, template_render_test.go, activitypub_test.go, and others) using stretchr/testify, with main_test.go conditionally running integration tests against a real MySQL instance via environment variables alongside default SQLite-backed unit tests — a fairly thorough dual-backend testing setup for a project this size. Error handling follows idiomatic Go conventions with explicit (value, error) returns wrapped through the impart package, and naming is consistently idiomatic Go. Visible CI is limited to a Docker image publish workflow, with no dedicated automated lint or test workflow apparent in the current GitHub Actions configuration, and a legacy Travis config remains from before the migration off Travis CI.

What Makes It Unique WriteFreely treats ActivityPub federation as a first-class, built-in property of a blogging engine rather than an optional plugin: every blog is independently discoverable and followable from Mastodon or other fediverse software through native webfinger and nodeinfo support, which is unusual among self-hosted publishing platforms that typically require an add-on for federation. It also natively supports Web Monetization payment pointers for streaming micropayments to writers, a standard most blogging competitors don’t implement at all. Paired with a single-binary, embedded-SQLite deployment model shared with the broader Write.as ecosystem, this keeps a federated publishing service unusually simple to operate.

Self-Hosting

Licensing Model AGPL-3.0 licensed — all features, including federation and multi-user support, are available in self-hosted deployments with no license keys or paid tiers.

Self-Hosting Restrictions None found — there is no ee/, enterprise/, or pro/ directory, and no license-check or feature-flag gating in the source that restricts functionality for self-hosters.

Enterprise Features None — there is no separate enterprise or paid tier in the codebase; the only official commercial option is the fully-managed Write.as hosting service run by the maintainers.

Cloud vs Self-Hosted Write.as (the hosted offering) provides managed installation, backups, and upgrades on top of the identical open-source codebase — it does not unlock additional features over self-hosting.

License Key Required No.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers