🚀 Executive Summary
TL;DR: Migrating extensive Standard Notes data to Notesnook manually is impractical and time-consuming. This guide provides a Python script that automates the conversion of a decrypted Standard Notes JSON export into a Notesnook-compatible format, enabling a quick and efficient data transfer in under 15 minutes.
🎯 Key Takeaways
- The migration requires a decrypted data export file from Standard Notes, not an encrypted one, to ensure the script can parse the content.
- The Python conversion script utilizes a two-pass system: first to map Standard Notes tag UUIDs to their titles, and then to process notes and correctly link them to the corresponding Notesnook tags.
- The process involves running a Python script (`migrate.py`) to generate a `notesnook_import.json` file, which is then uploaded directly into Notesnook’s built-in importer via Settings > Importer.
- Common pitfalls include using an encrypted Standard Notes backup, mismatches in the input file name (`standard_notes_export.json`), and accidental character encoding corruption if the output JSON is manually edited.
Migrate Standard Notes to Notesnook
Alright, let’s talk about tool migration. I’m a big believer in using the right tool for the job, and for a long time, Standard Notes was my go-to. Its commitment to simplicity and end-to-end encryption is fantastic. However, my workflow evolved, and I found myself needing the more robust feature set offered by Notesnook—better organization, a more modern editor, and superior attachment handling. The biggest roadblock was migrating several years of notes. A manual copy-paste job was out of the question.
So, I did what any of us would do: I wrote a script. This guide is the refined version of that process, designed to get your entire Standard Notes archive migrated over to Notesnook in less than 15 minutes. Let’s get it done.
Prerequisites
Before we start, make sure you have the following ready:
- Your decrypted data export file from Standard Notes (a single JSON file).
- Python 3 installed on your machine.
- Basic comfort with running a Python script from your terminal.
The Guide: Step-by-Step
Step 1: Export Your Data from Standard Notes
This is the most critical step. You need the decrypted backup, not the encrypted one.
1. Open your Standard Notes application (desktop or web).
2. Navigate to the “Account” menu.
3. Select “Data Backups” and then choose the “Download Decrypted” option.
4. This will give you a file, typically named something like `StandardNotes-Decrypted-Backup-….json`.
5. For simplicity, rename this file to `standard_notes_export.json` and place it in a new working directory.
Step 2: Prepare Your Python Environment
I’ll skip the standard virtual environment setup since you likely have your own workflow for that. The important part is to work in an isolated environment to keep your global packages clean.
The script we’re about to write uses the `json` and `uuid` libraries, which are part of the Python standard library, so you shouldn’t need to install anything extra with pip. Just make sure your Python 3 environment is active.
Step 3: The Conversion Script
Now for the core logic. Create a new file in your working directory named `migrate.py` and paste the following code into it. I’ll explain what it does right after.
import json
import uuid
from datetime import datetime
def convert_sn_to_notesnook(input_file, output_file):
"""
Reads a decrypted Standard Notes JSON export and converts it
to a Notesnook compatible JSON format.
"""
try:
with open(input_file, 'r', encoding='utf-8') as f:
sn_data = json.load(f)
except FileNotFoundError:
print(f"Error: The file '{input_file}' was not found.")
return
except json.JSONDecodeError:
print(f"Error: Could not decode JSON from '{input_file}'. Is it a valid decrypted export?")
return
notesnook_notes = []
notesnook_tags = []
tag_map = {} # Maps SN tag UUID to its title
# First pass: process tags to build a map
for item in sn_data.get('items', []):
if item.get('content_type') == 'Tag':
tag_uuid = item.get('uuid')
tag_title = item.get('content', {}).get('title')
if tag_uuid and tag_title:
tag_map[tag_uuid] = tag_title
notesnook_tags.append({'title': tag_title})
# Second pass: process notes and link tags
for item in sn_data.get('items', []):
if item.get('content_type') == 'Note':
content = item.get('content', {})
note_title = content.get('title', 'Untitled Note')
note_text = content.get('text', '')
created_at_str = item.get('created_at', datetime.utcnow().isoformat() + "Z")
# Convert timestamp to Notesnook's expected format if needed
# For this script, we'll pass it through as-is, assuming compatibility.
note_tags = []
for ref in content.get('references', []):
ref_uuid = ref.get('uuid')
if ref_uuid in tag_map:
note_tags.append({'title': tag_map[ref_uuid]})
new_note = {
'uuid': str(uuid.uuid4()),
'content': note_text,
'title': note_title,
'type': 'note',
'created_at': created_at_str,
'updated_at': item.get('updated_at', created_at_str),
'tags': note_tags,
'trashed': item.get('deleted', False)
}
notesnook_notes.append(new_note)
notesnook_export = {
'version': '2.0.0',
'notes': notesnook_notes,
'tags': notesnook_tags
}
try:
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(notesnook_export, f, indent=2, ensure_ascii=False)
print(f"Success! Conversion complete. Check for the file: '{output_file}'")
except IOError:
print(f"Error: Could not write to the output file '{output_file}'.")
if __name__ == '__main__':
sn_file = 'standard_notes_export.json'
nn_file = 'notesnook_import.json'
convert_sn_to_notesnook(sn_file, nn_file)
What This Script Does:
- Reads the Data: It opens and loads your `standard_notes_export.json` file.
- Two-Pass System: The script reads the file twice. The first pass is crucial—it finds all your tags and builds a simple map of their internal ID to their title (e.g., `{‘uuid-123’: ‘Work’}`).
- Processes Notes: The second pass goes through all the notes. For each note, it pulls the title, text, and creation date. It then looks at the note’s “references” (how Standard Notes links tags) and uses our map from the first pass to find the correct tag titles.
- Builds the Notesnook Structure: It constructs a new JSON structure that matches what Notesnook expects, populating a list of notes and a list of tags.
- Writes the Output: Finally, it saves everything into a clean `notesnook_import.json` file, ready for import.
Pro Tip: My script handles the most common `Note` and `Tag` content types. Standard Notes has other types like `Component` or `Theme` which are ignored here, as they have no equivalent in Notesnook. If you have custom note types, you might need to inspect your JSON and adjust the script’s logic.
Step 4: Run the Script and Import to Notesnook
1. Open your terminal and navigate to the directory containing your `migrate.py` and `standard_notes_export.json` files.
2. Run the script with the command: `python3 migrate.py`
3. If all goes well, you’ll see a success message and a new file named `notesnook_import.json` will appear.
4. Now, open Notesnook, go to Settings > Importer, select the “Notesnook” format, and upload your newly created `notesnook_import.json` file.
Notesnook will process the file, and all your notes and tags should appear, preserving their relationships.
Common Pitfalls
Here is where I usually mess up on the first try, so you can avoid it.
- Using the Encrypted Backup: I can’t stress this enough. If you export the encrypted file from Standard Notes, the script will fail with a `JSONDecodeError`. The file must be human-readable. Double-check that you selected “Download Decrypted”.
- File Naming Mismatches: The script is hardcoded to look for `standard_notes_export.json`. If you named your export something else, either rename the file or change the `sn_file` variable at the bottom of the script.
- Character Encoding Issues: The script reads and writes files using `UTF-8`, which handles international characters and emojis correctly. If you open and re-save the final JSON file in a basic text editor, it might accidentally change the encoding and cause the Notesnook import to fail. It’s best not to modify the output file manually.
Conclusion
And there you have it. A clean, automated way to migrate your entire note history. This process turns a potentially days-long manual task into a quick, 15-minute script run. You get to keep your valuable data while upgrading your toolset. In our line of work, efficiency is everything, and automating tedious tasks like this is a cornerstone of a solid DevOps mindset. Happy note-taking.
🤖 Frequently Asked Questions
âť“ How do I migrate my Standard Notes to Notesnook using this script?
Export your decrypted data from Standard Notes as a JSON file, rename it to `standard_notes_export.json`, place it in the same directory as the provided `migrate.py` script, run `python3 migrate.py`, and then import the generated `notesnook_import.json` into Notesnook via its Settings > Importer.
âť“ What are the advantages of using this script over manual migration?
This script automates the entire migration, converting years of notes and preserving tag relationships in minutes, significantly reducing the effort and potential for errors compared to a tedious, days-long manual copy-paste process.
âť“ What is the most common error encountered during this migration process?
The most common error is attempting to use an encrypted Standard Notes backup. The script specifically requires a decrypted, human-readable JSON export to successfully parse and convert your notes and tags.
Leave a Reply