Created
February 23, 2026 12:20
-
-
Save dnaeon/87427d319ae0b0a14bf7bf2bc0c49a77 to your computer and use it in GitHub Desktop.
Export org-roam notes to Hugo using Emacs Lisp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env emacs --script | |
| ;; | |
| ;; A utility script to export all my org-roam notes via `ox-hugo' | |
| ;; | |
| ;; The script expects the `HUGO_BASE_DIR', `ORG_ROAM_DIR' and `ORG_ROAM_DB' env | |
| ;; vars to be set. | |
| ;; | |
| ;; `HUGO_BASE_DIR' specifies the directory where org-roam nodes will be | |
| ;; exported. | |
| ;; | |
| ;; Upon successful completion the script produces the following directories. | |
| ;; | |
| ;; $HUGO_BASE_DIR/content/notes - contains the generated Markdown files | |
| ;; $HUGO_BASE_DIR/static/ox-hugo - contains static files, e.g. images | |
| ;; | |
| ;; In order to serve the notes generated by the script simply sync the Markdown | |
| ;; files and static files from the directories above to your Hugo installation. | |
| ;; | |
| (dolist (env-var '("HUGO_BASE_DIR" "ORG_ROAM_DIR" "ORG_ROAM_DB")) | |
| (unless (getenv env-var) | |
| (error (format "%s env var is not set" env-var)))) | |
| (require 'package) | |
| (package-initialize) | |
| (require 'org) | |
| (require 'cl-lib) | |
| (require 'ox-hugo) | |
| (use-package org-roam | |
| :ensure t | |
| :config | |
| ;; Configure path to the org-roam database and notes | |
| (setq | |
| org-roam-directory (file-truename (getenv "ORG_ROAM_DIR")) | |
| org-roam-db-location (file-truename (getenv "ORG_ROAM_DB")))) | |
| ;; My org-roam capture templates store the notes in `notes/YYYY/MM' directory | |
| ;; structure. | |
| ;; | |
| ;; When exporting to Markdown via `ox-hugo' the resulting links are invalid, | |
| ;; because they would point to `../MM/filename.md'. | |
| ;; | |
| ;; Since all files are being exported to the `$HUGO_BASE_DIR/content/notes' | |
| ;; directory we are simply stripping any leading directories from the filenames | |
| ;; here, in order to have valid links. | |
| (defun org-export-resolve-id-link/strip-directory (val) | |
| (car (last (file-name-split val)))) | |
| (advice-add 'org-export-resolve-id-link :filter-return #'org-export-resolve-id-link/strip-directory) | |
| ;; All my org-roam notes contain the `CREATED' property, which specifies the | |
| ;; creation date of the note. | |
| ;; | |
| ;; This wrapper adds the `:date' property to the export environment, which | |
| ;; `ox-hugo' will use when exporting to Markdown. | |
| ;; | |
| ;; Additional keys that may be added here include `:hugo-publishdate', | |
| ;; `:hugo-lastmod', etc. | |
| (defun org-export-get-environment/add-date (orig-fun &rest args) | |
| (let ((env (apply orig-fun args)) | |
| (created (org-entry-get nil "CREATED"))) | |
| (plist-put env :date created))) | |
| (advice-add 'org-export-get-environment :around #'org-export-get-environment/add-date) | |
| ;; Iterate through the org-roam nodes and export each of them | |
| (let* ((hugo-base-dir (file-truename (getenv "HUGO_BASE_DIR"))) | |
| (hugo-static-dir (file-name-concat hugo-base-dir "static")) | |
| (org-roam-nodes (org-roam-node-list)) | |
| (unique-roam-nodes (cl-remove-duplicates | |
| org-roam-nodes | |
| :key (lambda (node) (org-roam-node-id node))))) | |
| ;; ox-hugo expects that the $HUGO_BASE_DIR/static directory exists in advance. | |
| (unless (file-accessible-directory-p hugo-static-dir) | |
| (make-directory hugo-static-dir t)) | |
| ;; Export each org-roam node | |
| (dolist (node unique-roam-nodes) | |
| (let ((node-title (org-roam-node-title node)) | |
| (node-file (org-roam-node-file node))) | |
| (with-current-buffer (find-file-noselect node-file) | |
| (setq-local org-hugo-base-dir hugo-base-dir | |
| org-hugo-front-matter-format "yaml" | |
| org-hugo-section "notes" | |
| org-agenda-files nil | |
| org-export-with-broken-links t) | |
| (org-hugo-export-wim-to-md)))) | |
| (message (format "Exported %d org-roam node(s)" (length unique-roam-nodes)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment