From Dendron to Logseq

From Dendron to Logseq
Photo by Erda Estremera / Unsplash

If you read my previous post about moving to a new note-taking app, you'll know that I wanted to try out Logseq. However, I've got over 2,000 notes in Dendron, and there's no way I was either going to lose all that info or migrate by hand.

Fortunately, both Dendron and Logseq are Markdown-based. One of the huge reasons this is an advantage is because it means even if the app goes away, you're not trapped in some strange format that means you can't access data. The downside, though, is that Markdown is more of an agreement than a completely standardised format. There are different flavours, and slightly different ways of doing things. On top of that, Dendron and Logseq approach notes with a slightly different philosophy.

There's never a perfect migration, and my approach is to get the stuff across and readable, then tidy it up afterwards. There are always slightly different ways of doing things, and it's not always worth perfectly replicating notes from years ago as long as the data is there somewhere and shows up in a search. So this article covers how I've got to that basic stage.

The wood for the trees

Dendron's defining feature is hierarchies. It's right there in the name; a branching organised note repository. If you're a Dendron user, you're likely to have lots of files organised into a load of different trees. Dendron uses dots in the filename to mark the difference, so your files look like:

people.md
people.alice.md
people.alice.messages.md
people.bob.md
people.eve.md
books.md
books.python-for-pythons.md
books.cryptography-for-beginners.md

Dendron supports wiki-style links between notes, and the link is the same as the filename, minus the .md extension, e.g. [[people.alice]].

Logseq is much more of a networked thing, making more use of references and backlinks. However, it has a feature called namespaces which do a similar thing. At time of writing, the documentation on the official page is marked as a Todo.

Namespaces work pretty much the same as hierarchies in Dendron; both apps use a single folder full of files, and mark out differences in the name of the file. The only major differernce is the naming convention. Instead of separating layers of the hierarchy with a dot, Logseq uses a tripe-underscore character. So, the above note hierarchies look like this in Logseq:

people.md
people___alice.md
people___alice___messages.md
people___bob.md
people___eve.md
books.md
books___python-for-pythons.md
books___cryptography-for-beginners.md

Logseq also supports wiki-style links between notes, and thankfully doesn't expect you to type out the tripe-underscores each time, it just uses a forward slash instead, e.g. [[people/alice]].

Quick aside  - I've not found a way to replicate the Schema features that Dendron had, which gave structure to hierarchies in a different way, but there may be other approaches in Logseq - perhaps buttons with pre-defined actions - which can keep things consistent in the same way. Look out for more articles as I figure out Logseq some more!

One last wrinkle

Great, now you know how to move your files from Dendron to Logseq! But if you do, when you run the re-index command, you'll probably get a load of errors about clashing page titles. That's because both apps make use of frontmatter in the markdown files to store metadata about the note, but, once again, implement it slightly differently. The snag is the title property.

Dendron doesn't really care much about what you set your page title to; it uses the file name itself to manage everything about the file. You can have as many pages with the title as you like. Because of this, it defaults to making the page title the very last section of the whole note name. For example, the note people.alice.messages will have the title set to "Messages" when the note is created. Now, if you create another note, people.bob.messages. That will also have the title "Messages".

In Logseq, titles need to be globally unique. By default, you don't need to set a value at all, it's just the note filename in the wiki-style link format. However, if you do have a title attribute set, then you need to make sure it's unique. So all those files from Dendron with the same title value, need to be fixed.

Unless you've extensively changed your Dendron titles, the easiest way to handle that is to simply delete the whole title line from the note file, and then ammend it later on if you need it. If you have extensively changed your Dendron titles, then renaming the attribute to old-title or similar should at least get you up and running without losing the data.

Doing this automatically

There's no way I'd ever make all these changes for over two thousand notes. So I wrote a script to do it for me. This is very much in the quick-and-dirty, intending for single-use mode, so it doesn't have many niceties.

It should run with a plain Python install (anything later than 3.6 or so I think, though tested with 3.11), and on any platform (though tested on Windows 11).  No warranties, use at your own risk, always back up your data, look twice before crossing the road, etc...

To use the script:

  • Create a copy of all of the Markdown files in your Dendron vault that you want to migrate in a new folder. DO NOT USE THIS ON ORIGINAL FILES - you might lose your notes.
  • Create a text file with the contents of the script below, and run it with Python. The filenames should change to their new format.
  • Copy all of the Markdown files into your Logseq pages directory, and the run re-index on your graph.
""" Script to convert Dendron's native Markdown format to Logseq format

This script takes Markdown files created by Dendron, and converts them into a format that can be
dumped in the "pages" folder within Logseq. It's designed to be run from the same folder as the files
you want to convert. It will attempt to change all files with the .md file extension.

WARNING: Do not run this on your original Dendron files. Take a copy, then dump those converted files
into Logseq.

This script makes the following changes.
- Rewrites any wikilinks to slashes instead of dots.
- Removes Dendron's "title:" attribute from metadata, which causes name class errors when importing.
- Rewrites filenames to use Logseq's triple-underscore format instead of Dendron's dots.

"""
import re
from pathlib import Path

# Remove Title from metadata
def remove_title(file):
    temp_file = file.with_suffix('.tmp')
    with open(file, 'r', encoding="utf-8") as text_file :
        with open(temp_file, "w", encoding="utf-8") as output:
            filedata = text_file.readlines()

            frontmatter_count = 0

            for line in filedata:
                # Need to read metadata between the two ___
                    if frontmatter_count < 2:
                        if not line.startswith("title:"):
                            output.write(line)
                    else:
                        output.write(line)
                    if line == '---\n':
                        frontmatter_count = frontmatter_count + 1
    
    return(temp_file)

# Rewrite wikilinks
def rewrite_wikilinks(file):
    # Use regex to find all examples, then work through them with a straight string substituion
    with open(file, 'r', encoding="utf-8") as f:
        filedata = f.read()
    
    matches = re.findall(r'\[\[(.+?)\]\]', filedata)

    for match in matches:
        logseq_format_string = match.replace( "." , "/" )
        filedata = filedata.replace(match, logseq_format_string)
    
    with open(file, 'w', encoding="utf-8") as f:
        f.write(filedata)
    
    return file
    
# Save file in new format
def new_file(old_file):
    new_file_stem = old_file.stem.replace( "." , "___" )
    new_file_name = old_file.with_stem(new_file_stem)
    new_file_path = new_file_name.with_suffix('.md')
    old_file.rename(new_file_path)


p = Path('.')
markdown_files = list(p.glob('*.md'))

for file in markdown_files:
    fixed_title_file = remove_title(file)
    fixed_links_file = rewrite_wikilinks(fixed_title_file)
    Path(file).unlink()
    new_file(fixed_links_file)

What next?

Now everything's over in Logseq, the next step is to start using it. There are a lot of extensions, and other features that aren't available for Dendron, so I'm going to look at those soon. There are also a couple of things that I've not got set up yet but did exist in Dendron, so these are the things I'm planning to explore next:

  • Templates
  • Page properties
  • Todos and tasks
  • Page references
  • Buttons and automation

Do let me know if there's anything else you'd like to see!