🖋Migrating to Org-roam v2

The moment I learned about Org-mode v2 development some months back, I was skeptical. I decided I am not upgrading. Org-roam v2 has been released yesterday and I still decided that I am not upgrading.

What’s wrong? v2 supports id:-links only (no, no file links)—a controversial org-mode extension brought by org-id module. Org-id introduces globally-unique IDs to org-mode. That means that Emacs now has to track them, org-export doesn’t work unless you have indexed all the files with ids , and you also have to patch org-html for it to generate correct links. (Org-id implements persistent cache but this also brings issues when working on multiple computers.)

All in all, id:-links greatly reduce org-mode portability and interoperability with other tools. And that is something I care about.

Why I changed my mind

I’ve read Jethro’s Releasing Org-roam v2 post and also Boris Buliga’s Path to org-roam v2. I hit the sack with the thought that it’s all fine and good but there is no way that I am upgrading.

I mean, I support the idea of reducing org-roam’s core and providing better base for plugins, the new roam buffer looks cool, the perspective of scalable org-agenda is intriguing, and better performance is always welcome. But v2 also removed the support for directory-based tags, broke my config and templates, and yeah… no file-links support.

But I woke up today and somehow decided to give it a try. 🤷‍♂️

I could see how id-links could allow more freedom in note taking flow. Sure, you can rename files freely but that’s a minor improvement because org-roam v1 already patches all references. What’s more interesting is that you can create multiple notes within a file.

This allows for some interesting flows and refactorings:

  • You can have more wiki-like flow where you elaborate on a topic in a single page. But you can still treat headlines as separate notes, reference them independently or refactor them as described next.

  • If a file grows too big, you can migrate a headline-note as a new file-note (keeping all the references intact).

  • You can have a “kindergarten” file where you collect or develop your “infant” notes and migrate them to separate files when they prove to be interesting. (That’s a kind of writing inbox.)

And you know, id-links are not that bad. Org-roam keeps a database of all notes, so presumably I don’t need to track all ids separately. I am not using org-export, and Uniorg has been supporting id-links for a while now.

So yeah, I’m writing this post with org-roam v2.

The migration process

The migration process went relatively smooth. (See rasendubi/dotfiles@44ef581 · org-roam v2 migration for config changes.)

Org-roam provides an easy M-x org-roam-migrate-wizard command to migrate all your notes to v2. It backups your notes to org-roam.bak but it’s still a good idea to commit all your changes before you go down the migration road.

Somehow, org-roam-migrate-wizard did not migrate all my notes on the first run (only 20 or 30 notes were migrated). I deleted org-roam.bak and ran the wizard again and this time it worked fine—all notes migrated to the new org-roam format without any issue or additional manual work required.

Now for config changes, you should change → org-roam-setup.

there were a few command renames: org-roam-find-fileorg-roam-node-find, org-roam-insertorg-roam-node-insert, org-roam-switch-to-bufferorg-roam-buffer-toggle, etc.

Org-roam picked up some irrelevant headlines as notes (my spaced repetition flashcards), and I was prepared to dig into the source and patch org-roam, but I found that org-roam provides an option to filter-out headlines before adding them to database. The following snippet excludes all headlines with :fc: tag.

(setq org-roam-db-node-include-function
      (defun rasen/org-roam-include ()
        ;; exclude org-fc headlines from org-roam
        (not (member "fc" (org-get-tags)))))

There were some changes to capture templates but they weren’t too bad. One important note is that org-roam-bibtex now also uses org-roam-capture-templates.

Speaking of which, you need to update org-roam-bibtex to v0.6 which is not released yet, but should be pretty soon. I’ve installed it from org-roam-v2 branch for now. There is also a bug in org-roam-bibtex that prevents org-roam from creating non-bibtex notes: org-roam/org-roam-bibtex#194 fix: (wrong-type-argument stringp nil) when adding a non-bibtex note.

I also used directory-based tagging—having multiple directories in org-roam for different purposes, and org-roam v1 nicely prefixed all notes with (directory-name). The following snippet (adapted from Hitchhiker’s Rough Guide to Org roam V2) brings it back:

(cl-defmethod org-roam-node-filetitle ((node org-roam-node))
  "Return the file TITLE for the node."
  (org-roam-get-keyword "TITLE" (org-roam-node-file node)))

(cl-defmethod org-roam-node-hierarchy ((node org-roam-node))
  "Return the hierarchy for the node."
  (let ((title (org-roam-node-title node))
        (olp (org-roam-node-olp node))
        (level (org-roam-node-level node))
        (directories (org-roam-node-directories node))
        (filetitle (org-roam-node-filetitle node)))
     (if directories (format "(%s) " directories))
     (if (> level 0) (concat filetitle " > "))
     (if (> level 1) (concat (string-join olp " > ") " > "))

(cl-defmethod org-roam-node-directories ((node org-roam-node))
  (if-let ((dirs (file-name-directory (file-relative-name (org-roam-node-file node) org-roam-directory))))
      (string-join (f-split dirs) "/")

(setq org-roam-node-display-template "${hierarchy:*} ${tags:10}")

The new roam buffer looks cool and it even finds unlinked references if you ask it to (ripgrep recommended):

(setq org-roam-mode-section-functions
      (list #'org-roam-backlinks-section

That’s all I have to say for now. (Didn’t have a chance to use org-roam extensively yet.)

If you’re migrating, be sure to check Hitchhiker’s Rough Guide to Org roam V2, too.