ONLINEREV · 2026-06-23§ BLOG · 2026-06-19-SELF-HOSTED-EVERNOTE-REPLACEMENT-JOPLIN-AI-SEARCHPUBLISHED · 2026-06-19
All Posts
§ Journal2026-06-19

I Replaced a $250/yr Evernote Subscription With a Mac Mini That Answers Questions About My Notes

By Corey SlickPublished

Evernote wanted $250 a year. So I moved 12,690 notes to self-hosted Joplin on a Mac mini, then built an AI that actually answers questions across all of them — local embeddings, automatic voice transcription, native apps, ~$0 a month. Here's the whole build.

For about fifteen years, my working memory lived in Evernote: research notes, a daily journal, scanned documents, medication logs, clipped articles — 12,690 notes across 277 notebooks. In late 2025 the bill for that privilege hit roughly $250 a year, and the trajectory pointed one direction: more gating, higher prices.

So I left. I moved all 12,690 notes to a self-hosted setup running on a Mac mini in my office, kept native apps on iOS, macOS, and Android, and now pay essentially nothing per month to run it. Then I did the part Evernote never did well: I built an assistant that actually answers questions across the entire archive.

This is the whole build — the decision, the migration that nearly didn't work, the architecture, and the AI layer that was the real point.

The $250 trigger

I was on Evernote's Advanced tier (formerly "Professional"). When Bending Spoons restructured the plans in late 2025, the price of my tier jumped by roughly $80/year. Nothing about the product had improved for me — I'd just become more expensive to keep.

The deeper problem was lock-in. Fifteen years of notes is not a thing you idly migrate. Evernote knew that, and the pricing reflected it. I wanted out before the archive got any bigger, but I had hard requirements:

  • Apps on iOS, macOS, and Android. I capture on the phone, write on the Mac, read everywhere.
  • AI search that actually works — across every device, including the iPhone. This was my #1 need. Evernote's search consistently disappointed me, and "ask my notes a question" simply didn't exist.
  • Preserve my colored highlights, 100%. I color-code heavily. Losing the highlights would have made years of notes harder to use. Non-negotiable.
  • PDFs, voice notes with transcription, and a Home/scratchpad surface like the one Evernote put front-and-center.
  • Keep my existing daily-journal pipeline (an automation that emails entries into a notebook every morning) working against whatever replaced Evernote.

Build vs. buy: the actual decision

I weighed three paths:

  1. Buy a lifetime app (UpNote, ~$40 one-time). Cheap and done — but I'd be trading one closed box for another, with no AI story.
  2. Self-host open-source Joplin. Own the data and the backend, $0 recurring, but I'd have to build the parts Joplin lacks.
  3. Build the whole thing from scratch. Total control, and a multi-month detour to reinvent an editor and a sync engine that already exist and are battle-tested.

I chose #2, with a principle that shaped everything after: adopt vanilla Joplin for the hard 90%, and build only the high-leverage 10%.

Joplin already nails the 90% that's genuinely hard — a real Markdown editor, a robust sync engine, offline-first behavior, and three mature client apps. Reinventing that would be foolish. What it doesn't do well is exactly the 10% I cared about most.

The temptation was to fork Joplin's apps and bolt my features on. I rejected that fast. Joplin ships two to three releases a month touching the editor, sync, and import paths; maintaining a fork across three platforms is a permanent tax — re-signing and re-releasing the iOS build on every one of those releases, forever. No thanks.

There was one hard wall pushing me toward forking anyway: the stock iOS app only installs Joplin-team "recommended" plugins, so the community AI-search plugin can't run on the iPhone — the device I carry everywhere, for the feature I wanted most.

The insight that dissolved the whole problem: the AI work (embedding a 10 GB corpus, running a model) wants to run on the always-on Mac mini regardless. So instead of forking anything, I'd build the AI as one small server-side companion service on the mini, reachable from every device — including the iPhone — over my private network. That sidesteps the iOS plugin gate entirely, leaves all three Joplin apps stock and auto-updating, and gives me a single implementation to maintain instead of three forks.

The migration nobody warns you about

This is the part I'd underestimated. Moving 12,690 notes out of Evernote with fidelity turned out to be the hardest engineering in the project.

Evernote exports to ENEX files. Joplin imports ENEX. In theory, done. In practice:

  • Joplin's native ENEX importer aborted on malformed anchor tags and silently lost ~11% of my notes in testing. An 11% data-loss rate on an irreplaceable archive is a non-starter.
  • It also mangled highlight color spans — and preserving highlights was my hard requirement.
  • The popular third-party converter (Yarle) drops highlight colors too, and produced title collisions.

So I wrote my own ENEX → Markdown converter. A few things that made it work:

  • A tolerant streaming parser. Some of my per-notebook ENEX files are large enough to blow past Node's ~512 MB single-string limit, so the converter streams rather than reading whole files into memory.
  • Highlight detection. It finds Evernote's highlight markers and emits inline colored spans that render correctly on every platform — all five highlight colors intact.
  • Date preservation. Real created and modified timestamps carry over, not the import date. (This matters more than it sounds — sorting fifteen years of notes by "when I actually wrote this" is the difference between a usable archive and a pile.)
  • Graceful fallback. On any conversion edge case it falls back to preserving the raw HTML, so nothing is ever dropped for content I can't cleanly convert.

The result: 12,690 notes, 277 notebooks, 26 stacks, roughly 60,000 attachments — imported with zero errors. Colored highlights preserved across all 20 highlighted notebooks. Created and modified dates intact.

One hard-won lesson: run destructive import tests in a throwaway profile. An early test against my real sync polluted it with ~50,000 deletion records and forced a clean server reset. Migrations like this deserve a sandbox.

After import, OCR re-runs on the mini to rebuild a searchable text layer over scanned PDFs and images — Evernote's text layer isn't portable, so you regenerate it on your side.

Proving nothing was lost

Migrating fifteen years of notes is one thing. Trusting the migration enough to cancel the subscription is another. So before I cancelled anything, I audited it.

I wrote a script that compared all 12,690 notes — the original Evernote content, decompressed straight out of Evernote's own backup database, against what actually landed in Joplin — using a normalized word-and-sentence diff. The results:

  • Zero notes lost. Joplin actually ended up holding three more than Evernote; the handful of apparent title "misses" were just notes I'd renamed or moved over the years.
  • 607 notes showed content differences — almost entirely web clips and saved emails. Converting a captured web page's HTML into clean Markdown is inherently lossy (comment threads, navigation chrome, ad boilerplate). The pristine originals are preserved in the off-site archive regardless.
  • Exactly two hand-typed notes had real text drops. Both traced to two bugs in my converter's handling of deeply nested lists. I fixed both — the lesson being never return raw HTML from a Turndown rule; emit a placeholder and restore it afterward — and repaired the two notes back to 100%.

Two notes out of 12,690, both recovered. Combined with a full export of the original Evernote data archived to encrypted off-site storage, that was enough confidence to pull the plug.

The self-hosting architecture

The backend is deliberately boring, which is what you want from infrastructure:

  • Joplin Server (joplin/server + postgres:16) runs in Docker via colima on the mini, and starts itself on boot. All three stock clients sync to it.
  • Remote access goes through Tailscale, which issues a real, auto-renewing Let's Encrypt certificate for the server. This isn't a nicety — iOS won't trust a self-signed cert and gives you no "ignore TLS errors" escape hatch, and Android's equivalent toggle is buggy with Joplin Server. A genuine public CA cert was the only reliable path to the phones.
  • It's private-network-only. Nothing is exposed to the public internet — no forwarded ports, the database isn't published, and the only way in is my own tailnet.
  • The mini's always-on desktop Joplin is the workhorse. It generates OCR (a desktop-only feature) and exposes the local read-only Data API that my companion service indexes from. The phones keep attachment download on "manual" so they never try to pull the full multi-gigabyte library.

Because Joplin is offline-first, every device holds a complete local copy. If the mini reboots, sync just pauses — no data is ever at risk on the clients.

The 10% I actually built: "Ask My Notes"

This is the centerpiece, and the reason the whole project was worth it.

It's a small FastAPI service on the mini. The pipeline:

notes ──chunk──▶ Ollama (nomic-embed-text) ──▶ sqlite-vec  (local vector store)
query ──▶ semantic search + SQL-over-metadata + full-note read ──▶ Claude (ZDR) ──▶ cited answer
  • It pulls notes through the read-only Data API, chunks them, and embeds them locally with Ollama (nomic-embed-text), storing vectors in a single sqlite-vec file. The indexer is incremental and OCR-aware — it only re-embeds what changed.
  • Embeddings run locally on purpose. The corpus includes a personal journal with medication logs. That content never leaves my own hardware to be indexed.
  • Answers come from Claude, through a zero-data-retention endpoint, and always link back to the source notes they're drawn from.
  • It's agentic, not just similarity search. The model has three tools: semantic search, read-only SQL over a notes-metadata table, and full-note read. That combination means it answers content questions and arbitrary aggregations ("how many notes are in my daily journal?" → 158) and counts inside a single note ("how many injections did I log in May?" → 25). A plain vector search can't do the last two.

The front end isn't a web page — it's three native apps. One shared SwiftUI codebase targets both iOS and macOS; a Jetpack Compose app covers Android. All verified on real devices. Highlights:

  • Ask is a real multi-turn chat. The client owns the conversation transcript and posts the message history with each turn, so the server stays completely stateless.
  • Tappable citations open an in-app note reader.
  • Client-side sorting on the real Evernote created/modified dates (relevance, modified, created, title).
  • Bearer-token auth, with the token kept in the Keychain / encrypted storage.

One bonus that punched above its weight: synced favorites. Joplin has no native synced or mobile favorites — the desktop plugin is per-machine and doesn't sync. I migrated my exact 54 Evernote shortcuts and built a Shortcuts tab into the apps that reads and writes a synced "⭐ Shortcuts" note through the Data API. Add, remove, and reorder notes and notebooks on any device, and it syncs everywhere.

Voice notes, a real Home, and the files phones choke on

With search handled, the rest of the wishlist was about daily ergonomics — the small things that make a tool feel finished instead of merely functional.

Voice notes that transcribe themselves. A background worker on the mini watches for new audio notes and transcribes them with a local Whisper model (mlx-whisper, large-v3-turbo, running on the Mac's GPU). It appends a labeled 🎙️ Transcript section right into the note body — so the text appears everywhere the note does, and gets picked up by the same search index, which means I can find a voice memo by what I actually said in it. It runs locally for the same reason the embeddings do: some of those recordings are personal. On its first run it transcribed all 153 of my existing voice notes, and it's device-agnostic — it doesn't matter which phone or Mac recorded the audio.

A Home that actually feels like Evernote. Joplin has no Home surface on mobile, which is exactly where I missed it most. So the companion app got a native Home tab: a synced scratchpad that autosaves as you type, one-tap quick-capture into an auto-created 📥 Inbox notebook, and a live "recent notes" list. It's the cross-platform landing pad Evernote always had and stock Joplin never did.

The big files phones can't sync. Joplin's mobile apps refuse to sync any single attachment over 100 MB, so a handful of large PDFs and a couple of videos were simply invisible on my phone. The companion serves them on demand instead: a per-note attachments list plus a global "large files" browser, backed by a range-aware streaming proxy on the mini. Tap a file and it downloads and opens in the native viewer (QuickLook on iOS and macOS, the system viewer on Android). Nothing big ever downloads unless I ask for it.

Backups, and what happens if the mini dies

A self-hosted system you can't restore is a liability, not an upgrade — so backups got real attention.

Every night, the Joplin database is dumped and pushed to Cloudflare R2 through restic, client-side encrypted before it ever leaves the machine (~11 GiB stored), with 7-day / 4-week / 6-month retention and a weekly integrity check. The job is self-healing: it probes the destination first and repairs a stale network tunnel before giving up, rather than silently failing at 3 AM. And — the step most backup setups skip — I actually performed a restore and verified it. The mini runs FileVault for at-rest encryption.

Combined with Joplin's offline-first model, total loss of the mini means "restore from R2," not "lose fifteen years of notes." Every client still holds its own full copy in the meantime.

The economics, and what I gave up

The headline number: ~$250/year → ~$0/year recurring. It runs on a mini that's already on for other work, the embeddings and voice transcription both run locally, and the only metered cost is Claude API calls for answers — cents, not dollars.

But self-hosting isn't free in every sense, and it's worth being honest about the trade-offs:

  • No sharing, collaboration, or real-time co-editing. This is a single-user system by design. If you need a team workspace, this isn't it.
  • No handwriting/ink capture, and no in-app PDF annotation. Joplin has no path for these; I annotate PDFs in an external app.
  • Single-host availability. If the mini is down, sync pauses. Offline-first softens this — I keep working on-device and it catches up — but there's no 99.99% SLA behind it. It's my mini.
  • The real cost was build time. Adopting Joplin for the hard 90% is the only reason this was tractable. Had I tried to build the editor and sync engine too, I'd never have finished.

For me the math is easy: a one-time build, on hardware I already run, in exchange for owning my archive, keeping a sensitive corpus on my own machines, and finally having an assistant that can actually answer questions across fifteen years of notes.

The subscription I finally cancelled

With the iPhone fully synced, my colored highlights rendering correctly in the app's note reader, the entire original Evernote export archived to encrypted off-site storage, and an audit that compared all 12,690 notes and came back clean — I cancelled the $250-a-year subscription.

What this was really about isn't note-taking apps. It's that you can replace a polished commercial product with self-hosted open source plus a focused slice of custom code, and come out with more than you started with: AI search that actually works, automatic voice transcription, your data on your own hardware, encrypted backups you've genuinely test-restored — and no annual bill. The whole trick was refusing to rebuild the 90% that already exists and spending every bit of the effort on the 10% that doesn't.

This is part of what I do with AI at Slick Engineering & Consulting, Inc. — build my own custom infrastructure that's tailored precisely to my own needs.