Meta - Migration Workflows

Don’t think Drafts works as a mobile FE - see here --> How do I work with Obsidian on Mobile?

I wrote a simple action to Send to Obsidian with Tags.

I wrote a Python script that converts every row of all CSV files in the working directory and subdirectories into markdown files according to the formatting settings you choose per column.

You can:

  • add everything as YAML frontmatter
  • choose the delimiter of your CSV files
  • the maximum file name length
  • from which column the file name should be generated
  • choose the markdown formatting for each column
  • write the chosen settings to
  • or read settings you set before.

It will let you choose the settings for the first file in the list of CSV files it creates, so all the CSV files you run it on have to have the same columns if you want the settings to be applied consistently/if you want it not to fail. (This means that you should only run the script on CSV files with the same number of rows/formatting at once and choose different settings for the next batch.)

This script may be helpful if you want to transfer your data from programs that can export to CSV. The script should give you the best of both worlds. Markdown with its linking, tags and graph view (from Obsidian) and, optionally, all the info as YAML which you can query with dataview to preserve the advantages of a database.

Please consult the Readme for information on installation and updates to the script.
This post will most likely not be updated. To get an up-to-date overview of the features, please follow the link to the repo and read the Readme.

If you find any bugs/have feature requests, please open an issue in the repo.

1 Like

OPML (XLM) import to Obsidian

OPML is a common format for nested lists (i.e. outliners).

You may be tempted to try pandoc --from opml --to gfm, but unfortunately it interprets nested lists as headings, and converts each nesting level to a heading level. This is wrong. Maybe you’re OK with that format, but this guide is how to turn it into a true outline (hierarchical nested list).

Here is how to get the nested list into obsidian

  1. Log in to and start at a blank document. Note that Dynalist is the other product the Obsidian developers maintain, and thus why this conversion works well.
  2. Open your OPML file in a text editor and copy the whole thing
  3. Paste into the Dynalist document. This automatically runs a parser in the background to convert it into Dynalist format. You should see a nested list.
  4. click the hamburger menu (3 lines near the title) and click Export.
  5. click the Formatted tab. Copy the entire contents.
  6. Paste into an Obsidian document. This automatically runs are parser in the background and should result in a properly nested list in Obsidian.
  7. Done


This topic may be of interest


  • Migration from Note-Station
  • Markdown migrations
    • Convert between different types of Markdown
  • HTML to Markdown conversion
  • Markdown to HTML

Uses pandoc for part of the conversion but also handles the parts of files pandoc does not convert through some pre and post processing of files.

Hope it’s of help to somebody.

Latest update 1.6.0 adds features to help identify and trouble shoot issues in the note sets and allows more flexibility over file locations

version 1.6.0 additional options allow you to

  • change absolute links to images and attachment so relative paths
  • Choose any folder as the source
  • Choose any folder as an export location
  • Generates a conversion report that warns of issues with file links in the note sets. This helps you identify notes that may not be fully converted.
  • Management of orphan files - orphan files are images/documents that are in the source folders but were not linked in any notes. This helps clean out old data or identity items that should be linked but are not.

Sections of the conversion report may include the following:

  • Invalid links
    • links in the notes that are not recognised as being valid
  • Orphan files
    • list of orphan files that were not linked to in any of the notes
  • Missing attachments
    • list of images of attachments such as pdf’s that were linked to but the files themselves could not be located
  • List of attachments that are using absolute links
  • For NSX conversion
    • List of note pages where the attachments’ data key was set to null in the export. This is an issue with the note station export into the nsx file not being complete. Can be seen where there are synchronisation issues between the web and desktop versions.
    • List of note pages that were encrypted and could not be converted

Migration from Standard Notes to Obsidian

Quick explanation:

  • Export Standard Notes to Text (Download Backup - Decrypted)
  • Import txt files to Bear, then export as Markdown to your Obsidian vault

Export from Standard Notes Desktop
From the app

  • Click on Account
  • Under Data Backups, choose Decrypted
  • Click Download Backup, and save in a folder of your choice

Import into Bear

  • Download Bear if you need to, then open
  • Click File > Import Notes
  • Bear doesn’t have file names, only titles, so choose “Use File Name as Title”. No point clicking on “Keep Original Creation and Modification Date” as all the exported text files will have the same creation and modification date.
  • Select all the notes you want to export
  • File > Export Notes
  • Choose Export As: Markdown
  • Export Notes to a folder of your choice


  • Once you have your notes from all your old services in 1 folder, use that as the Obsidian vault.

New on Obsidian and new to this forum, so forgive me if this has already been discussed before (I did a quick search, but I couldn’t find anything about what I’m about to write).
The topic, of course, is migrating from Roam to Obsidian, and I have a (quite) big graph “locked” in some EDN/JSON file.
I tried importing all my graph in Logseq (don’t ask me how I stumbled in this workaround… too long story) and then opening Logseq directory with Obsidian.

Everything is there and correctly (back)linked!!!

I did a quick “tour” of my notes and I only found some minor glitches with {{alias:SOMETHING… and with (arbitrary) id’s appended to blocks due to a Table of Content creator plugin I installed, but this seems to me the easiest path to Obsidian from Roam.

Anyone else tried this? How did you manage to solve glitches?

Thank you so much @Silver, this makes coming from Ulysses so much easier!

Here’s a NodeJS script I’m working on to migrate from Dynalist to Obsidian.

It connects to the Dynalist API and converts documents into Obsidian compatible MD files.

Haven’t tried this but it looks handy for migrating from Notion:

Onenote to Obsidian converter

Saw this on Reddit and thought I’d post it here. I haven’t tried it.

RealmWorks to Obsidian converter (authored by me):

1 Like

Migrating from Windows sticky notes: Liberating and Importing Microsoft/Windows Sticky Notes - #3 by EleanorKonik

1 Like

Eleanor suggested I could post this blog post of mine about my experience transitioning from Roam Research to Obsidian:

Converting OneNote to Obsidian:

I used nixsee’s script to convert my notes. It was not plug and play though, so I documented here what I needed to do to make them work in Obsidian.

1 Like

I’ve compiled, organized, and updated much of the material on this “Meta - Migration Workflows” page into one consolidated article shown here: The Road from Roam to Obsidian. The road from Roam Research (Roam) to… | by Denise Todd | Mar, 2022 | Medium Hope it helps someone.

1 Like

How about RemNote…?

Is there any methods to transfer data from remnote to obsidian? (with a clear explanation?)

I see non in this post :frowning:

I found this link, but can’t seem to work it out by myself…

I’ve also posted remnote related question in a separate post, but it’s only been a few hours. Hope I can receive help from this post!!

Thanks in Advance~

The migration flow above from standardnotes to Obsidian didn’t work for me.
So I’ve wrote simple python script, that migrates notes and tags structure.


import json
from argparse import ArgumentParser
from pathlib import Path

import os

def _parse_args():
    description = """Migrates standardnotes unencrypted backupfile to the obsidian compatible, markdown tree folder structure.
If tags are enabled - convert tags to front matter yaml notation.
First tag found on the note - converted to note folder, preserving tag structure in the file system.
    argument_parser = ArgumentParser(description=description)

    argument_parser.add_argument('--output', type=str, help='Output folder. Defaults to input folder', default=None)
    argument_parser.add_argument('--skip-tags', dest='skip_tags', action='store_true', help='Ignores tags.', default=False)
    argument_parser.add_argument('input', type=str, help='Standardnotes backup folder')

    args = argument_parser.parse_args()

    return args

def prepare_notes_content(items, root_folder):
    notes = {}
    for item in items:
        if item['content_type'] != 'Note':

        content = item['content']['text']
        for clean_rich_text_words in [
            '<p dir="auto">',
            content = content.replace(clean_rich_text_words, "")

        notes[item['uuid']] = {
            'title': item['content']['title'],
            'content': content,
            "tags": [],
            "folder": ""
    return notes

def _prepare_tags_parents(tag_folder):
    tag_parents = {}

    for tag_file in tag_folder.glob("*.txt"):
        with open(tag_file, "r") as f:
            tag_data = json.load(f)

        tag_uuid ="Tag-", "").replace(".txt", "")
        tag_parents[tag_uuid] = {
            "parent": None,
            "title": tag_data['title']
        for reference in tag_data['references']:
            if reference['content_type'] != "Tag":

            parent_uuid = reference['uuid'].split("-")[0]
            tag_parents[tag_uuid]['parent'] = parent_uuid

    return tag_parents

def prepare_tags(backup_folder, notes):
    tag_folder = Path(backup_folder) / "Items" / "Tag"

    if not os.path.isdir(tag_folder):

    tag_parents = _prepare_tags_parents(tag_folder)

    for tag_file in tag_folder.glob("*.txt"):
        with open(tag_file, "r") as f:
            tag_data = json.load(f)

        references = tag_data['references']
        for reference in references:
            if reference['content_type'] != 'Note':
                item = notes[reference['uuid']]
            except KeyError:
                print(f'Wrong tag reference: missing uuid {reference["uuid"]}')

            tag_uuid ="Tag-", "").replace(".txt", "")
            current_tag = tag_parents[tag_uuid]

            folder = current_tag['title']

            while current_tag['parent']:
                current_tag = tag_parents[current_tag['parent']]
                folder = f"{current_tag['title']}/{folder}"

            if not item['folder']:
                item['folder'] = folder


def write_output(output, notes):
    output_destination = Path(output) / "markdown_migration"

    for item in notes.values():
        create_folder(output_destination / item['folder'])
        file_name = (output_destination / item['folder'] / item['title'].replace(
            " ", "_"
            ).replace("/", "_")).with_suffix('.md')

        with open(file_name, "w") as f:
            if item['tags']:
                for tag in item['tags']:
                    f.write(f"  - {tag}\n")


    print(f"Output written to f{output_destination}")

def create_folder(folder):
    if os.path.isdir(folder):
    except Exception:

def main(backup_folder, output=None, skip_tags=False):
    if output is None:
        output = backup_folder

    with open(Path(backup_folder) / "Standard Notes Backup and Import File.txt", "r") as f:
        backup = json.load(f)

    items = backup['items']
    notes = prepare_notes_content(items, output)

    if not skip_tags:
        prepare_tags(backup_folder, notes)

    write_output(output, notes)

if __name__ == '__main__':
    args = _parse_args()
    main(args.input, output=args.output, skip_tags=args.skip_tags)

Hey Korvyashka, sorry for the late reply.

Just to clarify, do I just need to download that file and run it in terminal with the same directory to convert all my remnote files into obsidian??