🚀 Executive Summary

TL;DR: This guide addresses the problem of Bear Notes vendor lock-in by providing a script-based solution to migrate an entire Bear library, including attachments, to Joplin. The process enables users to move their notes to an open-source, cross-platform note-taking application, ensuring accessibility beyond the Apple ecosystem.

🎯 Key Takeaways

  • A Bear Pro subscription is essential for exporting notes along with their attachments, which is a critical prerequisite for a complete migration.
  • The migration workflow involves exporting Bear notes as Markdown with attachments, followed by a Python script that converts Bear’s asset linking structure to Joplin’s ‘Raw Directory’ format.
  • The Python script renames assets with unique UUIDs, updates internal links from Bear’s `(assets/filename)` to Joplin’s `(:/{resource_id})`, and embeds Joplin-specific metadata (ID, timestamps) into each note file.
  • Joplin’s ‘Raw Directory’ import expects notes as individual `.md` files and all associated attachments within a `_resources` subfolder at the root of the import directory.
  • The final step involves using Joplin’s ‘File > Import > RAW – Joplin Export Directory’ feature to ingest the converted `joplin_import` folder, integrating all notes and their attachments into the application.

Migrate Bear Notes to Joplin (Cross-platform)

Migrate Bear Notes to Joplin (Cross-platform)

Hey team, Darian here. Let’s talk about vendor lock-in. I was a huge fan of Bear for years—it’s a beautiful note-taking app. But I hit a wall when my workflow expanded beyond the Apple ecosystem. Being unable to access or edit my notes on my Linux build server or Windows machine became a significant bottleneck. Manually moving notes was out of the question. I needed a better way.

After a bit of digging, I settled on Joplin. It’s open-source, end-to-end encrypted, and works everywhere. The only hurdle was the migration. This guide is the result of that process—a clean, script-based workflow to move your entire Bear library to Joplin, attachments and all. It saved me hours of manual work, and I hope it does the same for you.

Prerequisites

Before we start, make sure you have the following ready:

  • Bear Pro Subscription: You need the Pro version to export your notes with their attachments.
  • Joplin Desktop App: Download and install it from the official Joplin website.
  • Python 3: A recent version of Python should be installed on your system.

The Guide: Step-by-Step

Step 1: Export Your Notes from Bear

First, we need to get a clean export of your data. This is the most critical step, as the quality of our migration depends on it.

  1. Open the Bear app on your Mac.
  2. In the sidebar, select the notes you want to migrate. To select all of them, just click in the notes list and press Cmd+A.
  3. Navigate to the menu bar and select File > Export Notes…
  4. In the export dialog, configure these two crucial settings:
    • Export As: Markdown
    • Check the box for: Export attachments
  5. Choose a location to save the export. Bear will create a folder containing all your notes as .md files and a subfolder named assets for all your images and file attachments. Let’s call this our bear_export directory.

Pro Tip: I recommend creating a dedicated project folder for this migration, something like bear-to-joplin-migration. Place your bear_export folder inside it. This keeps everything tidy.

Step 2: Prepare Your Python Environment

Alright, time to prep our workspace. I’m going to skip the usual directory creation and virtual environment setup commands, as you likely have your own preferred workflow for that. We’ll jump straight to the logic.

The core of this migration is a Python script that will convert Bear’s Markdown format into a structure Joplin can understand, called the “Joplin Raw Directory” format. This format is simple: each note is a .md file, and all attachments live in a shared _resources folder.

Step 3: The Conversion Script

Here’s the Python script that will do the heavy lifting. It reads your Bear export, processes each note, and rebuilds it for Joplin. I’ve added comments to explain what’s happening at each stage.

Save this code as migrate.py in your project folder.


import os
import re
import shutil
import uuid
import datetime

# --- CONFIGURATION ---
# Point these to your directories
BEAR_EXPORT_DIR = 'bear_export'
JOPLIN_IMPORT_DIR = 'joplin_import'
# ---------------------

def get_file_metadata(filepath):
    """Gets creation and modification time for Joplin metadata."""
    stat = os.stat(filepath)
    created_time = datetime.datetime.fromtimestamp(stat.st_ctime).isoformat(timespec='milliseconds') + 'Z'
    modified_time = datetime.datetime.fromtimestamp(stat.st_mtime).isoformat(timespec='milliseconds') + 'Z'
    return created_time, modified_time

def convert_bear_to_joplin():
    """Main function to run the migration."""
    print("Starting migration from Bear to Joplin...")

    # Create the Joplin output directories
    joplin_resources_dir = os.path.join(JOPLIN_IMPORT_DIR, '_resources')
    if os.path.exists(JOPLIN_IMPORT_DIR):
        shutil.rmtree(JOPLIN_IMPORT_DIR)
    os.makedirs(joplin_resources_dir)

    bear_assets_dir = os.path.join(BEAR_EXPORT_DIR, 'assets')

    # Process each Markdown file in the Bear export directory
    for filename in os.listdir(BEAR_EXPORT_DIR):
        if not filename.endswith('.md'):
            continue

        print(f"Processing note: {filename}")
        
        note_title = os.path.splitext(filename)[0]
        source_note_path = os.path.join(BEAR_EXPORT_DIR, filename)

        with open(source_note_path, 'r', encoding='utf-8') as f:
            content = f.read()

        # Regex to find Bear's asset links, like [image.png](assets/image.png)
        # It captures the asset filename.
        asset_links = re.findall(r'!\[.*?\]\(assets/(.*?)\)', content)

        for asset_filename in asset_links:
            source_asset_path = os.path.join(bear_assets_dir, asset_filename)
            
            if not os.path.exists(source_asset_path):
                print(f"  - WARNING: Asset not found: {asset_filename}")
                continue

            # Create a unique ID for the Joplin resource
            resource_id = uuid.uuid4().hex
            file_ext = os.path.splitext(asset_filename)[1]
            joplin_asset_filename = f"{resource_id}{file_ext}"
            dest_asset_path = os.path.join(joplin_resources_dir, joplin_asset_filename)

            # Copy the asset to the Joplin resources folder
            shutil.copy2(source_asset_path, dest_asset_path)

            # Replace the Bear link with the Joplin resource link
            bear_link = f"(assets/{asset_filename})"
            joplin_link = f"(:/{resource_id})"
            content = content.replace(bear_link, joplin_link)

        # Create the Joplin note file with metadata
        created_ts, updated_ts = get_file_metadata(source_note_path)
        joplin_note_id = uuid.uuid4().hex
        
        joplin_md_content = f"""{note_title}

id: {joplin_note_id}
created_time: {created_ts}
updated_time: {updated_ts}
user_created_time: {created_ts}
user_updated_time: {updated_ts}
source: bear-migration-script

{content}
"""
        
        joplin_note_filename = f"{note_title.replace(' ', '_')}.md"
        joplin_note_path = os.path.join(JOPLIN_IMPORT_DIR, joplin_note_filename)

        with open(joplin_note_path, 'w', encoding='utf-8') as f:
            f.write(joplin_md_content)

    print("\nMigration complete! Your notes are ready in the 'joplin_import' directory.")
    return 0

if __name__ == '__main__':
    convert_bear_to_joplin()

Step 4: Run the Script

Make sure your Bear export folder is named bear_export and sits alongside the migrate.py script. Then, open your terminal, navigate to your project directory, and run the script:

python3 migrate.py

The script will create a new folder named joplin_import. Inside, you’ll find all your converted .md files and a _resources subfolder containing all the renamed attachments.

Step 5: Import into Joplin

This is the final step. We’ll hand off our perfectly formatted directory to Joplin.

  1. Open the Joplin desktop application.
  2. Go to the menu and select File > Import > RAW – Joplin Export Directory.
  3. A file dialog will open. Select the joplin_import folder that our script created.
  4. Joplin will process the import. Depending on the number of notes, this might take a few moments.

Once it’s done, you’ll see a new notebook in Joplin containing all your migrated notes, with their attachments correctly linked and displayed.

Common Pitfalls

Here are a couple of things I’ve learned to watch out for:

  • Forgetting to Export Attachments: This is the most common mistake. If you forget to check “Export attachments” in Bear, the script will run but will print warnings about missing assets, and you’ll end up with broken image links in Joplin.
  • Incorrect Directory Names: The script is hardcoded to look for a bear_export directory. If you named your export something else, either rename the folder or update the BEAR_EXPORT_DIR variable in the script.
  • Character Encoding Issues: The script assumes UTF-8, which is standard. If you have notes with very unusual characters, you might encounter an encoding error. It’s rare but possible.

Conclusion

And that’s it. You’ve successfully broken free from a single-vendor ecosystem and moved your valuable knowledge base to a flexible, open-source platform. Your notes are now truly cross-platform and future-proof. This script provides a solid foundation; you can easily extend it to handle tags or other specific metadata if needed. Hope this helps you streamline your workflow.

— Darian Vance

Darian Vance - Lead Cloud Architect

Darian Vance

Lead Cloud Architect & DevOps Strategist

With over 12 years in system architecture and automation, Darian specializes in simplifying complex cloud infrastructures. An advocate for open-source solutions, he founded TechResolve to provide engineers with actionable, battle-tested troubleshooting guides and robust software alternatives.


🤖 Frequently Asked Questions

âť“ How do I migrate my Bear Notes to Joplin, ensuring all attachments are included?

First, ensure you have a Bear Pro subscription. Export your notes from Bear as Markdown, making sure to check the ‘Export attachments’ option. Then, use the provided Python script to convert this export into Joplin’s ‘Raw Directory’ format, which handles asset renaming and link updates. Finally, import the resulting ‘joplin_import’ directory into the Joplin desktop application via ‘File > Import > RAW – Joplin Export Directory’.

âť“ How does this script-based migration compare to manual methods or other tools for moving notes to Joplin?

This script-based migration offers a robust and automated solution for transferring an entire Bear library, including all attachments, to Joplin. It significantly outperforms manual note-by-note transfers in terms of efficiency and accuracy, directly addressing vendor lock-in by providing a clean, open-source, and cross-platform alternative to Bear, which manual methods often fail to achieve comprehensively for attachments and metadata.

âť“ What are the most common issues encountered during the Bear to Joplin migration process?

The most common pitfalls include forgetting to select ‘Export attachments’ during the Bear export, which results in broken links in Joplin. Another common issue is incorrect naming of the `bear_export` directory, as the Python script is hardcoded to look for this specific folder. Rare character encoding issues might also occur with unusual characters, though the script assumes standard UTF-8.

Leave a Reply

Discover more from TechResolve - SaaS Troubleshooting & Software Alternatives

Subscribe now to keep reading and get access to the full archive.

Continue reading