This guide migrates a Bichon v0.3.7 installation to the v2.x storage architecture. It is run interactively through the bundled bichon-admin tool and is non-destructive — every legacy file is read and copied, nothing is modified or deleted.
How to tell you are on v0.3.7
Your data directory looks like this:
<root-dir>/ # the value of --bichon-root-dir
├── meta.db # accounts, users, roles, OAuth2, proxy, tokens
├── mailbox.db # mailbox records
├── envelope/ # Tantivy index — envelope metadata
└── eml/ # Tantivy index — raw message dataThe giveaway: in v0.3.7 both the metadata and the raw email bytes lived inside Tantivy indexes. envelope/ and eml/ contain meta.json plus .store / .term / .idx / .fieldnorm / .pos files.
What the migration does
Two steps, run in order by the same menu option:
- Metadata — reads
meta.dbandmailbox.dband writes everything into the newmemdb/store: mail settings, accounts, OAuth2 entities and tokens, proxy settings, user roles, users, access tokens, and mailboxes. This step runs first and aborts the whole migration (without touching anything) if either legacy database is missing. - Emails — walks every segment of the legacy
eml/index, re-ingests each raw message into the v2.x stack: mail and attachment Tantivy indexes are rebuilt, attachments are re-detached from the message bodies, and all raw blobs go into the bichon-blob engine. Messages whose envelope record is missing are skipped and reported, not silently dropped.
When it finishes, a STORAGE_VERSION file containing 2 is written — that is what tells the v2.x server the data is current.
The v2.x layout you end up with
<root-dir>/
├── STORAGE_VERSION # contains "2"
├── memdb/ # accounts, users, roles, mailboxes, tokens…
├── bichon-indices/
│ ├── mail_metadata/ # Tantivy mail index
│ └── attachment_metadata/ # Tantivy attachment index
├── bichon-storage/
│ └── blobs/ # bichon-blob engine — raw EML + attachment blobs
├── tmp/ logs/ exports/ backup-staging/ # runtime directoriesCustom directory configurations
⚠ Read this before starting if your old server used custom paths. Bichon supports splitting storage across locations with
--bichon-index-dir/--bichon-data-dir(env varsBICHON_INDEX_DIR/BICHON_DATA_DIR). If yours did and the paths are handled inconsistently, the migration can succeed while the server later comes up showing an empty archive.
1. Find out what your old server used. Check the startup configuration before touching anything — docker inspect <container> (look for BICHON_INDEX_DIR / BICHON_DATA_DIR in Env), your docker-compose.yml, systemd unit, or launch script. In a default setup neither is set, and the legacy index/data live at <root>/envelope and <root>/eml.
2. Answer the tool's prompts with the old server's exact values. The tool asks for --bichon-root-dir, --bichon-index-dir and --bichon-data-dir. If the old server had custom values, type them here — the tool verifies the legacy Tantivy index exists at that exact path (it is not smart about guessing; a wrong path aborts with "No legacy v0.3.7 storage layout was detected" and changes nothing).
3. Know where the new data lands. The new v2.x directories are created inside the directories you entered, not inside the root:
| Setting | Legacy data at | New v2.x data at |
|---|---|---|
--bichon-index-dir=/ssd/envelope | /ssd/envelope (Tantivy index) | /ssd/envelope/bichon-indices |
--bichon-data-dir=/hdd/eml | /hdd/eml (Tantivy index) | /hdd/eml/bichon-storage |
4. Start the new server with the same flags. This is the critical part. The v2.x server resolves its paths the same way — <index-dir>/bichon-indices, <data-dir>/bichon-storage — so it finds the migrated data only if you keep passing the identical flags (-e BICHON_INDEX_DIR=/ssd/envelope -e BICHON_DATA_DIR=/hdd/eml in Docker).
⚠ The empty-archive trap: the migration writes
STORAGE_VERSION=2into the root directory no matter where the data lives. If you then start the v2.x server without the custom flags, the version check passes, the server happily creates fresh empty directories under<root>, and the WebUI shows an empty archive — while your data sits untouched at the custom locations. Stop the server immediately in that state, restart it with the correct flags, and the archive reappears. Do not let IMAP accounts re-sync into the empty archive in the meantime.
The cleanup step (below) also moves accordingly: after verification, delete the legacy envelope/ and eml/ content at the custom locations, not under the root.
Step-by-step
1. Get the server into a stopped-but-reachable state
Upgrade to the v2.x image/binary and start it. It detects the legacy layout and enters maintenance mode — the WebUI shows a 503 page and the container keeps running. That is the state you want: docker exec now works.
In the default Docker setup the data directory is
/datainside the container. All paths the tool asks for are container-internal paths when you run it viadocker exec.
2. Start the tool
docker exec -it <bichon-container> bichon-admin(or ./bichon-admin from the install directory on a bare install)
Select "Migrate Legacy v0.3.7 Storage to v2.x (bichon-blob)".
3. Answer the path prompts
| Prompt | Default (Enter to accept) | Notes |
|---|---|---|
--bichon-root-dir | — (required) | Must exactly match what the old server used. In Docker: /data |
--bichon-index-dir | <root>/envelope | Only override if the old server had a custom index dir |
--bichon-data-dir | <root>/eml | Only override if the old server had a custom data dir |
The tool verifies a v0.3.7 Tantivy layout exists at those paths. If it reports "No legacy v0.3.7 storage layout was detected", your paths are wrong (or the data is already newer) — nothing has been changed; re-run with corrected paths.
4. Confirm, pick a batch size
You are asked for a batch size, which controls peak memory during the email phase:
| Batch size | Approx. RAM | |
|---|---|---|
| 1000 | ~500 MB | slower, low memory |
| 3000 | ~1 GB | recommended (default) |
| 5000 | ~2 GB | faster, high memory |
If your mailbox holds many large attachments, pick a smaller batch size. Actual usage depends on average email size.
5. Watch the progress
The tool processes the legacy eml/ index segment by segment with a progress bar (a scan phase per segment, then the migrate phase). Warnings like eid <n> envelope not found are individual messages that could not be attributed and were skipped — note them; they will not exist in the new archive.
6. Restart and verify
docker restart <bichon-container>The server now starts normally. Verify in the WebUI that your accounts, mailboxes, and message counts look right, and that search works.
7. Clean up (only after verifying)
Once you are confident the new install is healthy, the legacy files can be removed to reclaim disk space:
<root-dir>/envelope/ <root-dir>/eml/ <root-dir>/meta.db <root-dir>/mailbox.dbDo not delete them before verification — they are your rollback plan.
Troubleshooting
| Symptom | Meaning / fix |
|---|---|
"Legacy metadata database not found at <root>/meta.db" | The root directory does not point at the v0.3.7 install. Nothing was modified; re-run with the right path |
| "No legacy v0.3.7 storage layout was detected" | envelope/ / eml/ at the given paths are not Tantivy index dirs — check the custom --bichon-index-dir / --bichon-data-dir values the old server used |
| Skipped count > 0 in the summary | Messages without a matching envelope record were not migrated. Check the per-message WARN lines during the run |
| Migration interrupted (Ctrl-C, OOM, power loss) | The legacy files are untouched, so nothing is lost. Before re-running, delete the partially written new directories — <root>/memdb, <root>/bichon-indices, <root>/bichon-storage/blobs — then start the option again; it rebuilds them from scratch. (Do not delete meta.db, mailbox.db, envelope/, eml/.) |
| Server still shows the 503 page after restart | STORAGE_VERSION was not written (the tool prints an error if this fails). Check docker logs and re-run the migration |
Disk space
The migration writes a complete new copy of your archive (blobs are re-compressed with zstd, so the new copy is often smaller), while the legacy files stay in place. Have at least as much free space as your current archive size before starting.