GrainFed

What's new

The work since the first numbered release, by theme, newest concerns first. Everything here is in the source with the tests that prove it; this page is the plain-language version.

Where to get it. This is the current source. The published 0.1.0 binaries predate most of it, so to run what is described here, build from source — one command, and nothing but Go is needed.

October 2026

Fasterperformance

The instance's counts are cached, for as long as you say. The number of people and posts on the landing and about pages, in /api/v1/instance and in NodeInfo used to be counted from the database on every request. On a small server that was the slowest thing it did. They are now kept, and a figure that has expired is still shown while a fresh one is counted in the background, so no visitor waits for it.

The lifetime is a setting: System settings → Performance. Two hours is recommended and is the default. Pixelfed itself keeps these for twelve hours, and the page says so. Zero turns the cache off; the most is a day.

Saferfederation

  • A stricter check on account-deletion messages. When a server announces that one of its accounts is gone, the check that the message really came from that account is now tighter. Found by reading the code, not by an attack, and fixed with a test. It is the reason to build from source rather than run the 0.1.0 binary, and a new release will carry it.
  • Dead accounts stop being retried. A suspended or deleted account's server keeps delivering its "I was deleted" message for ever, and each one was answered with an error that means try again later. The production log held about 9,300 of them. A deletion from an account nobody here has heard of is now answered once with "received" and dropped: there is nothing to remove.

Admin panelfixes

  • A decided application shows its outcome, not the tools for deciding it. Once a curated-registration application is approved or rejected, the page says so, links to the person's account, and no longer offers approve, reject or resend as if it were pending.
  • A client could not register on the API. POST /api/v1/apps, which every Mastodon-style app calls first, failed on any instance whose .env did not set BCRYPT_COST — the same defect that had broken registration and password resets, found a second time in the production log. It is fixed where the cost is used, so no caller can miss it.
  • The new logo is in the admin panel, the web interface and the sign-in page, and the accent colour is its orange.

September 2026

Pixelfed 0.14.4compatibility

  • Pinned to 0.14.4. Every route 0.14 added is served, the configuration tables follow its renamed environment variables (the old spellings keep working, because a real .env uses them), and the version a peer or a crawler sees is the Pixelfed release GrainFed claims. A database still at the 0.12.9 baseline is reported as supported, not behind.
  • Direct messages read and write the new dm_* tables when they exist, keep the older path when they do not, and never create the tables themselves. Federation, notifications, reports and account purge all follow.
  • NodeInfo reports the Pixelfed release rather than the Mastodon API version it used to — a mistake found only by looking at the live instance after deploying.

Federationstandards

  • Follower synchronisation (FEP-8fcf), so a follower list stays consistent between servers instead of drifting.
  • Quote posts (FEP-044f), as the server that authorises them, with the interaction-policy API and a privacy page. Consent lives in GrainFed's own tables.
  • Featured collections (FEP-7aa9) and block synchronisation (FEP-070c), each in both directions where there are two.
  • Direct messages carry context and conversation on the way out.

Sign-up and sign-insecurity

  • The 0.14.4 login flow. Nobody has a session until the password, the second factor and the email check have all passed, and a deep link survives the steps.
  • Captcha with three providers — hCaptcha, Cloudflare Turnstile and Cap — switchable per surface (login, register, password reset, curated application, in-app sign-up), with a choice of whether it fails open.
  • A honeypot on registration, a ban on sign-up and sign-in from cloud-provider addresses, and a user limit.
  • A minimum age (16 by default, an instance setting): the register form asks, and the curated application has the rules page and the age gate. The date of birth is read in the browser and never sent.
  • Curated applications email the administrators — all of them or the ones you name — when an applicant confirms their address, and a failure to send can never spoil that confirmation.
  • Email verification is one thing everywhere: the login flow, the resend on the settings page, registration, and admin invites.
  • In-app sign-up follows 0.14.4: an app that registered a client gets a token and a working refresh token against it, the redirect_uri is checked against your allowlist of schemes, and errors name their code.

Stabilityfound by running it

  • Two things at once. MariaDB 11.6 and later refuses a transaction that writes a row another has changed since it began, and a pair of them can deadlock. Twelve people blocking one account at the same moment failed most of the time, and the production log held two such failures on the queue. Writes now run again a bounded number of times, as Laravel's own transactions do.
  • An unset BCRYPT_COST made every registration and password reset fail, and a waiving admin invite did nothing on an instance that enforces email verification. Both fixed after being found in use.
  • Older in-app sign-up created accounts verified where verification is not enforced, and answered a bad link in the wrong field for the app to read. Fixed.

Before that0.1.0

The first numbered release: every servable route, the admin panel and settings tree, the web interface, the job queue and scheduler in the binary, and the adopt, doctor, probe, parity and optimize commands. The migration and install pages describe them.

Migrate an instance Read the source