One weird trick I use to upgrade GoToSocial
2026-01-26
GoToSocial?
For the past year and a bit, I've been relying on a one-user GoTosocial server for my fediverse participation. Fediverse is the 'well, actually' technically correct name for the social network protocols that power an overlapping set of free, distributed social networks that a lot of people just call 'Mastodon'. Mastodon is the largest and most popular server software used in this network, and got a significant bump in popularity when that crazy space junkie guy started hacking on twitter.
Monoliths vs Microliths
Mastodon is a large Ruby on Rails project, with the typical kind of architecture you might expect from a classic LAMP-adjacent dynamic web thing that's used in production to run instances with thousands and thousands of active posting user accounts, and a hefty server footprint.
Gotosocial is a fediverse server that specifically targets a lower footprint installation. It's written in Go, which while not being the kewlest platform to build a modern web server application in, is to my eyes, a pleasingly pragmatic choice. (Something I often like to say is 'Go is actually kind of a DSL for building small network servers in'). It also targets full mastodon compatibility, so it's a drop in replacement for a mastondon account, and much simpler to run if you were interested in having your own fediverse service.
WASM-azing!
Whilst Gotosocial has a modest footprint, and a few moving parts, it's not without some interesting technical architectural decisions. In one of its simpler installable forms, rather than use an external relational database like PostgreSQL, it just uses good old SQLite3 😍 - and rather than pay the CGO / boundary penalties for linking directly into SQLite as a shared library, it can actually run SQLite as a contained WASM process inside the go application, using the Wazero runtime
I adore everything about this approach, it's exactly the kind of mad science I'd try to get a simpler working service. End result is you have a single static binary that you can run and install, and it manages its own fully compatible SQlite3 database store in-process, without any install-or-link-time dependencies.
So it's super simple to install for me on linux, I simply need to unpack a binary linux release tarball and then launch the newer binary with the old database file. Gotosocial applies database migrations on startup.
Official upgrade procedure
Here's their offical upgrade instructions taken from codeberg for the binary release
- Stop GoToSocial
- Back up your database! If you're running on SQLite, this is as simple as copying your sqlite.db file, eg., cp sqlite.db sqlite.db.backup
- Download and untar the new release, including the web assets and templates, not just the binary
- Edit your config.yaml file as necessary (see the release notes)
- Start GoToSocial
- Wait for migrations to run.
It's about as simple as a manual upgrade can be.
My Tweaked upgrade procedure.
Well, aside from scripting it, I think there's one small improvement that can be made. So far as I know, GoToSocial doesn't (yet?) run auto vacuum on its SQlite database. VACUUM on SQLite is a necessary maintenance procedure that's used to refresh, compact and optimize the database backing store after it's been amended in use for some time. You can think of it a bit like a 'defrag' or a 'garbage collecter' for your database.
Without auto-vacuum, vacuum is necessarily a blocking operation, you will block all other database changes until the vacuum is done. As such it's ideal for downtime. So vacuuming your GoToSocial database when you upgrade is a good idea, although it does extend your service downtime by a couple of minutes.
So, as well as copy your database to a backup, I suggest you also connect to it, with the sqlite3 command and run a complete VACUUM. But wait, we can be even cleverer.
VACUUM INTO
Vacuum already makes a complete copy of the database. Go back and read the VACUUM documentation I linked above. You might also notice that SQLite VACUUM supports a 'VACUUM INTO' form, which materializes this vacuum copy information into a fresh database file.
so my amended system upgrade is like this, pretending for the sake of example that it's a manual process.
- chdir to my gotosocial directory
/gotosocial - download the new tarball release
- stop gotosocial with
systemctl stop gotosocial - rename the old
gotosocialbinary to a versioned backup - untar the new release and assets into the directory
- rename
gotosocial.sqliteto a versioned backup name e.g.gotosocial.backup.sqlite - connect to the newly renamed sqlite database with the
sqlite3 ./gotosocial.backup.sqlitecommand - run
VACUUM INTO 'gotosocial.sqlite'(i.e. re-creating an optimised gotosocial database) - start gotosocial again
systemctl start gotosocial - watch the migrations and startup with
journalctl -f -u gotosocial - profit!