mastodon-to-bluesky

python bluesky mastodon social-media howto

2025-06-14

I've been using Bluesky more and more recently. It's a pleasant enough place to post, though I'm still not entirely convinced by the AT Protocol, but that's a topic for another day).

As I've been spending more time on Bluesky, I realised I wanted to bring over my old posts from Mastodon. Manually copying and pasting everything seemed tedious, especially with image attachments and thread structures. So I wrote a tool to automate the process.

It's a command-line Python application, on Github. It handles fetching your Mastodon posts, converting the content, downloading media attachments, splitting long posts into threads, and posting everything to Bluesky.

I've tried to make it as robust and feature-rich as possible, including things like incremental transfers (so you can run it multiple times without creating duplicates), a dry-run mode for testing, filtering options, and automatic retry logic.

I've packaged the tool using the uv tool, which I find really convenient for managing command-line utilities. If you haven't used uv before, go and learn about that. I promise it's more important than migrating your social posts. As follows:

uv tool install mastodon-to-bluesky

For one-time use, you can use uvx:

uvx mastodon-to-bluesky transfer --help

Or, if you prefer the traditional pip approach:

pip install mastodon-to-bluesky

You'll need access tokens for both Mastodon and Bluesky. The README on Github has detailed instructions for obtaining these. Once you have them, the basic transfer command looks like this:

uvx mastodon-to-bluesky transfer \
--mastodon-instance https://your.mastodon.instance \
--mastodon-token YOUR_MASTODON_TOKEN \
--bluesky-handle you.bsky.social \
--bluesky-password YOUR_BLUESKY_APP_PASSWORD

You can store your credentials in a configuration file or use environment variables.

There are also various options for controlling the transfer process. For example, to do a dry run without actually posting anything to Bluesky:

uvx mastodon-to-bluesky transfer --dry-run

Or to transfer only posts from a specific date range:

uvx mastodon-to-bluesky transfer --since 2024-01-01 --until 2024-12-31

The tool handles downloading media attachments (up to four images per post, due to Bluesky's limitations) and splitting long posts into threads. It tries to preserve as much of the original formatting as possible, including mentions, hashtags, and links.

One of the things I focused on was making the tool robust. It tracks transferred posts to avoid duplicates and has automatic retry logic with exponential backoff for handling rate limits and transient errors.

There are some limitations, mainly due to differences between the Mastodon and Bluesky platforms. For example, Bluesky doesn't support backdating posts, so all transferred posts will have the current timestamp. The original Mastodon timestamp is appended to each post.

I'm pretty happy with how the tool turned out. It scratched my own itch, and hopefully it'll be useful for others migrating from Mastodon to Bluesky. It's another example of how quickly you can build this kind of software with LLM assistance. The whole project took about 3 hours from start to finish.