Open-source project
org-roam/org-roam avatar
org-roam/org-roam

org-roam: Roam-style backlinks inside Org-mode

Rudimentary Roam replica with Org-mode

6,054 stars490 forksEmacs LispGPL-3.0

At a glance

What is it?
org-roam is an Emacs Lisp package that adds bidirectional links and a graph view to Org-mode, storing notes as plain text files you keep offline. Its install paths are unusually well documented, its Doom Emacs story comes with a version pin you are told not to remove, and the repository calls itself a rudimentary replica.
Who is it for?
Pick org-roam if your notes already live in Org-mode and you want links and a graph without leaving Emacs, and read the manual before you change org-roam-directory. Skip it if you want a finished replica rather than a stated subset of Roam, or if you need an editor other than Emacs, since every documented install path is an Emacs package path.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Emacs Lisp, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • org-roam/org-roam6,054 ★ · +24
Star history
Repository2026-09-232026-11-14
org-roam/org-roam6k6.1k

24 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Backlinks and a graph instead of a folder hierarchy

org-roam is a plain-text knowledge management system written in Emacs Lisp, licensed GPL 3 or later, that takes some of Roam's features and places them inside the Org-mode ecosystem. The organising idea comes from the Zettelkasten method: notes reference each other instead of nesting inside one another, so nothing depends on where a file happens to sit in a directory tree. Two mechanisms follow from that choice. Backlinks let you move through notes by following references rather than by opening folders, and a built-in graph visualization is there to surface connections you had not planned. The deployment story is deliberately local. The wiki is edited completely offline, kept in your own control, written in plain text, and can be encrypted with GPG. For someone already running Org-mode as a personal wiki, the project presents itself as a plug-and-play addition rather than a migration.

file-truename is not optional when org-roam-directory is a symlink

One configuration trap is stated in a single sentence, and it bites anyone whose notes live behind a symbolic link. Org-roam does not resolve a symlink to org-roam-directory by itself, so the sample configuration wraps the value in file-truename: (org-roam-directory (file-truename "/path/to/org-files/")). Copy the sample without that call and the package reads a path that is not the real one. The dependency list is short and worth reading before anything else: org, with 9.6 named as the minimum required version, then emacsql, then magit-section.

Four routes to install, ending with a hand-set load-path

The install section is organised by how you manage packages, which is the right axis, because the cost of each route is different. package.el takes a single keystroke sequence from MELPA or MELPA Stable:

code
M-x package-install RET org-roam RET

straight.el takes a form instead:

emacs-lisp
(straight-use-package 'org-roam)

Doom Emacs has its own route, covered in its own section, because it hinges on a flag and a pin. The fourth route uses no package manager at all: clone with git or download the latest release, install the three dependencies by hand, then point Emacs at the code with two load-path lines. The extensions directory has to be on that list. Every source-level recipe in this project loads it with :files (:defaults "extensions/*"), so a load-path without it gives you a partial package.

Doom pins org-roam to a commit and asks you to leave it pinned

Doom's :lang org module knows about org-roam but leaves it switched off, because Doom pins the package to one specific commit for stability. Enabling it means editing $DOOMDIR/init.el to pass the +roam flag to the org module, written as (org +roam), saving the file, and running doom sync -u in your shell. The pin is deliberate and the project says so plainly: the unpin form is documented, flagged as not recommended, and paired with the advice to ask Doom to bump the package instead. Two escape hatches exist if you need them.

emacs-lisp
(unpin! org-roam)
(package! org-roam)

The first drops the pin. The second installs from a recipe repository such as MELPA rather than Doom's own recipe, and the same form also accepts :pin "commit hash" so you can pin it yourself. The recipe forms mirror the straight.el ones, including the local-repo variant for a fork, and each one repeats the extensions directory in its files list.

Six commands land under the C-c n prefix

The sample configuration is a use-package form with three parts that matter separately. :custom sets org-roam-directory and nothing else. :bind attaches six commands to the C-c n prefix: org-roam-buffer-toggle on l, org-roam-node-find on f, org-roam-graph on g, org-roam-node-insert on i, org-roam-capture on c, and org-roam-dailies-capture-today on j, which is the dailies entry point. :config is where display formatting goes.

emacs-lisp
(use-package org-roam
  :ensure t
  :custom
  (org-roam-directory (file-truename "/path/to/org-files/"))
  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n g" . org-roam-graph)
         ("C-c n i" . org-roam-node-insert)
         ("C-c n c" . org-roam-capture)
         ;; Dailies
         ("C-c n j" . org-roam-dailies-capture-today))

The :config part of that sample sets org-roam-node-display-template with propertize, and the comment ties it to people running a vertical completion framework. Those six bindings cover the loop the package is built around: open the buffer, find a node, look at the graph, insert a reference, capture a thought, log today.

One slash is missing from the load-path sample

The no-package-manager route ends with two load-path lines, and the second one is wrong as printed. It reads "/path-to-org-roam/extensions/" with no slash between path and to, while the line above it uses /path/to/org-roam/. Copy that line verbatim into a config and the extensions directory never joins load-path, which matters because it is the directory every source-level recipe asks for. The surrounding steps are correct and worth following in order: clone with git or take the latest release, satisfy org, emacsql and magit-section, set load-path, then issue the (require 'org-roam) call. Two extras arrive with the source tree: .texi files for the Emacs Info system, installed by hand following the manual, and a doc/ directory that the build can turn into documentation.

The Makefile delegates everything to eldev

Development tooling at the top level is thin on purpose. The Makefile opens with a comment saying it is mostly a convenience for CI and distributions and that eldev can be invoked directly instead, then delegates every target. lint, test and clean call eldev, prepare prepares the package, and docs, html and install-docs recurse into doc/. The clean, prepare, lint and test targets depend on an eldev-check rule that first verifies the binary exists and otherwise fails with a message pointing at the Eldev installation page. The library code is split by concern into org-roam.el, org-roam-node.el, org-roam-db.el, org-roam-id.el, org-roam-capture.el, org-roam-migrate.el, org-roam-mode.el, org-roam-log.el, org-roam-utils.el and org-roam-compat.el, with tests/ beside them, CHANGELOG.md at the root and BACKERS.md next to it. The repository is not archived, and the last push was on 2026-04-27.

Rudimentary by its own description, and Emacs is the only host

The project's own words set the ceiling. The repository description calls it a rudimentary Roam replica, and the introduction promises some of Roam's more powerful features rather than all of them. That framing matters when you evaluate the graph view, the backlink handling or the dailies, because none of them is offered as a finished equivalent of the product being copied. The second limit is the host. Every documented route into this package is an Emacs package route: MELPA, straight.el, a Doom module flag, or a hand-set load-path. The primary language is Emacs Lisp, the bindings are Emacs key sequences, and the buffer, capture and dailies commands are interactive commands, so there is no editor outside Emacs in this documentation. Migration code exists as org-roam-migrate.el, and the manual, not the README, is where the full picture sits.

Editorial conclusion

Pick org-roam if your notes already live in Org-mode and you want links and a graph without leaving Emacs, and read the manual before you change org-roam-directory. Skip it if you want a finished replica rather than a stated subset of Roam, or if you need an editor other than Emacs, since every documented install path is an Emacs package path. Check first that your org version is 9.6 or newer, that you can supply emacsql and magit-section, and whether Doom's commit pin already gives you the commit you want.

Frequently asked questions

How do I install org-roam?

From MELPA or MELPA Stable with package.el, using M-x package-install RET org-roam RET, or from straight.el with (straight-use-package 'org-roam). Without a package manager, clone the source with git or download the latest release, add the package directory and its extensions/ directory to load-path, then issue (require 'org-roam).

How do I install org-roam in Doom Emacs?

Doom's :lang org module has support for org-roam but does not enable it by default. Pass the +roam flag to the org module in your $DOOMDIR/init.el, for example (org +roam), save the file, then run doom sync -u in your shell.

What is Emacs org-roam?

A plain-text knowledge management system written in Emacs Lisp that brings some of Roam's more powerful features into the Org-mode ecosystem, following Zettelkasten principles for non-hierarchical note-taking. Your wiki stays local, can be encrypted with GPG, and is licensed GPL 3 or later.

How do I use org-roam day to day?

The sample configuration binds org-roam-buffer-toggle, org-roam-node-find, org-roam-graph, org-roam-node-insert, org-roam-capture and org-roam-dailies-capture-today under the C-c n prefix. A video by David Wilson of System Crafters introduces the basic commands.

Is org-roam dead?

The repository is not archived and the last push was on 2026-04-27. The releases are v2.3.1 from 2025-06-26, v2.3.0 from 2025-05-25 and v2.2.2 from 2022-04-25, and support still runs through two Slack channels, Discourse and GitHub issues.

Official sources

  1. License: GPL-3.0
  2. org-roam/org-roam on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/org-roam-org-roam.svg)](https://hysenlabs.com/projects/org-roam-org-roam)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/org-roam-org-roam.svg)](https://hysenlabs.com/projects/org-roam-org-roam)

Was this useful?