Migrating a Mozilla SeaMonkey profile to Firefox

Many years ago, the Mozilla browser development effort (which originated as an open-source version of the Netscape Navigator browser) split into two branches: SeaMonkey, which maintained the browser/mail/news/chat "communication suite" functionality of the Netscape Communicator product, and Firefox, which stripped out the non-browser components and focused specifically on browser development. Over time, the majority of Mozilla's development effort moved to Firefox, with only a small group of volunteers continuing to maintain SeaMonkey.

I personally have been using web browsers since the NCSA Mosaic days, transitioning through Netscape to SeaMonkey, and I had continued using SeaMonkey even after the Firefox split primarily out of preference for its more technically-oriented interface over Firefox's more user-oriented presentation (though I only used SeaMonkey's browser component, with an occasional moment of frustration when I accidentally opened its HTML editor and it prompted me to publish changes to someone else's website). However, perhaps partly from the unfortunate passing of one of the remaining SeaMonkey developers, the development of SeaMonkey has almost completely stalled, and for me, it became little more than a bookmark store and search engine interface from which I copied URLs into a separate Firefox instance.

Prompted in part by a mysterious delay on exit which sometimes prevented starting a new instance, in part by a sporadic crash on startup inside the JavaScript executor following a recent rebuild, and in part by Gentoo Linux dropping formal support for Python 3.11 (the latest version of Python on which SeaMonkey's build tools still run), I decided in early 2026 to "bite the bullet" and discard SeaMonkey in favor of Firefox. As both browsers stem from the same original project, there is still a high degree of compatibility between their profile formats, and I was able to carry over my SeaMonkey profile data mostly intact. This document describes the steps I took to transfer the data between profiles.

1. Create a new Firefox profile

Rather than attempting to start Firefox on the SeaMonkey profile and "see what broke", I created a clean profile with the current Firefox version, then copied prefs.js and chrome/* from the existing Firefox profile I had been using for incompatible sites.

(While my existing Firefox profile already had this option set, it is worth noting that Firefox 69 and later require the preference toolkit.legacyUserProfileCustomizations.stylesheets set to true in order to honor chrome/*.css stylesheets. See Mozilla bug 1541233.)

2. Find preference changes and apply as desired

Effectively: diff -u seamonkey-prefs.js firefox-prefs.js

In performing this step, I took the position that I would accept any changes in defaults between current SeaMonkey and current Firefox versions, and thus I was only interested in any settings I had changed from their defaults—which is precisely the content of the prefs.js file. Of the differences in the two files, there ended up being a fairly even balance between (1) changes I had made in my SeaMonkey profile but not my Firefox profile, which I applied to the new profile; (2) preferences which had changed name or structure from SeaMonkey to Firefox; and (3) SeaMonkey settings which no longer existed in Firefox (many of these were related to the non-browser components).

3. Migrate the places database

Early in its development, Firefox discarded the older bookmarks.html bookmark list and history.db history file in favor of a combined "places" database, places.sqlite. SeaMonkey also adopted this partway through its development, but because the browser component of SeaMonkey is based on a very old version of Firefox, simply copying the SeaMonkey places.sqlite file into the Firefox profile directory causes Firefox to discard the database due to data schema incompatibility.

Firefox does include logic to upgrade old places database files, but the logic only goes back to format version 52 (as set with the SQLite statement "PRAGMA user_version"), while SeaMonkey's format is version 42. While I could potentially have downloaded intermediate, older Firefox versions to upgrade in multiple steps (though with no guarantee those older versions would run in a modern environment), I instead chose to update the database file directly using an interactive sqlite session.

Firefox's logic for maintaining the places database is found in toolkit/components/places/Database.cpp. Specifically, the function Database::InitSchema() handles upgrading older places.sqlite versions by applying appropriate changes (SQL statements) to convert each version to its successor. I followed the commit history back to the point where logic supporting format version 42 was removed (revision 558258), then manually executed the SQL statements for each upgrade step to version 45.

The upgrade steps for several subsequent versions made use of functions defined in native code and called from SQL, so at that point I copied the update code removed in revision 674567 into an existing Firefox source tree and rebuilt Firefox with that change (along with a few auxiliary changes required to make the build work, notably removing the "Unused <<" idiom no longer supported in the current codebase and copying over the implementation of navHistory->RecalculateOriginFrecencyStats()). The resulting Firefox binary was able to load my modified places.sqlite file and update it to the current schema with (at least superficially) no apparent data loss.

4. Copy remaining data manually

Browser preferences and bookmark/history data cover the majority of profile data; the remainder is local site storage, autofill data, TLS certificates, and custom stylesheets. Of these, both browsers offer explicit TLS certificate export/import, and custom stylesheets are simple .css files which can be copied directly into the target profile); I chose to simply discard the rest, as I don't use autofill functionality in the first place and I clear local storage (including cookies) on browser close for most sites, leaving only a few lost cookies which could be easily re-established with fresh logins on the relevant sites.


Andrew Church
Last modified: 2026/1/8