I want to be able to create a function that splits or exports every single headline in a org mode file (recursively) into a separate file.

Ideally that would be a .md file but I can also live with a .org file

Does anyone have any examples on how to achieve this? Previous answers found here/org forums were focused only on top level headers and had issues with looping over the file.

to illustrate this org file:

* Title of Heading 1
  Text 1

** Sub-Heading 2
   Text 2

* Title of Heading 2
  Text 3

would result in the files

Title of Heading 1.md
Sub-Heading 2.md
Title for Heading 2.md

1 Answer 1


If a region is active org-md-export-as-markdown exports the region only.

So we have to

  • loop through each headline
  • set the active region
  • export the region to a markdown buffer
  • and finally use the title to save it
(defun my-org-export-each-headline-to-markdown (&optional max-level scope)
  "Export each headline in the current buffer to a separate markdown file.
The title of each headline is used as the filename. Existing
files are overwritten.
With a prefix argument MAX-LEVEL, only headlines up to the specified level will
be exported.
If SCOPE is nil, the export will be performed on the entire buffer.
For other valid values of SCOPE, refer to `org-map-entries'."
  (interactive "P")
  (when max-level (setq max-level (format "LEVEL<=%s" max-level)))
  ;; Widen buffer temporarily as narrowing would affect the exporting.
       ;; Loop through each headline.
        (lambda ()
          ;; Get the plain headline text without statistics and make filename.
          (let* ((title (car (last (org-get-outline-path t))))
                 (dir (file-name-directory buffer-file-name))
                 (filename (concat dir title ".md")))
            ;; Set the active region.
            (set-mark (point))
            ;; Export the region to a markdown file.
            (with-current-buffer (org-md-export-as-markdown)
              ;; Save the buffer to file and kill it.
              (write-file filename)
        max-level scope)))))

Then use M-x my-org-export-each-headline-to-markdown to export the headlines of the current buffer. If you want to export headlines up to a certain level call it with a prefix arg C-u 1 M-x my-org-export-each-headline-to-markdown.

You probably want to add this to the top of your org file to not get a table of contents:

#+OPTIONS: toc:nil
  • that’s perfect @Hubisan!
    – zeltak
    Commented Jan 17, 2020 at 14:49
  • Can we apply your solution only for the top header starting with * and not for the sub-headers?
    – alper
    Commented May 25, 2023 at 10:30
  • @alper added an option to set the max level for exporting.
    – Hubisan
    Commented May 26, 2023 at 11:59
  • Thanks! Is it possible to set max level as the default option as well?
    – alper
    Commented May 26, 2023 at 13:29
  • 1
    @alper either you make a wrapping function that calls the function like this (my-org-export-each-headline-to-markdown 1) or just replace the last line with: "LEVEL=1" scope))))
    – Hubisan
    Commented May 26, 2023 at 17:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.