A super lightweight note taking app that feels native everywhere.
A free, open source, offline-first notes app for macOS, Windows and Linux — with a Finder-style column browser, unlimited folder nesting, a rich text editor, instant full-text search, and optional Google Drive sync. No account, no subscription, no telemetry.
Most note apps ask you to adopt their sync service, their account, and their file format before you can write a sentence. MonkiNotes does the opposite:
- Your notes are a file you own. One SQLite database on your disk. No account, no server, no telemetry.
- The cloud is opt-in. Google Drive sync exists, is off by default, and runs against your OAuth client — nothing routes through a third party.
- It stays out of the way. No editor framework, no UI kit, no toolbar clutter. The window is a browser, an editor, and a status line.
- It looks like it belongs. Native menus, native context menus, native dialogs, platform keyboard conventions, and a strictly neutral light/dark palette.
The browser is a Miller column view, the same interaction Finder uses. Click a folder and its contents open in the next column to the right — at any depth.
Crucially, the browser never shows more than five columns at once. Going deeper scrolls the window rightwards; clicking back into an earlier column re-renders the columns behind it and drops everything to its right. A ten-level hierarchy stays as readable as a two-level one.
- Drag the divider between columns to widen or narrow either side
- Drag items between columns to re-file them; drop onto a folder row to move inside it
- ← steps back up the hierarchy, Enter renames, Delete removes
- Cycles are impossible — a folder can't be dropped into its own descendant
- Deleting a folder removes its subtree in a single cascading transaction
Right-click a row or the empty space of any column to get a native menu with New Note and New Folder, created in that column. Item menus add open, rename, duplicate, export, and delete. There is no "new" button anywhere in the chrome, and no starter document — the app opens empty and stays that way until you write something.
A proper rich text editor with an icon toolbar — bold, italic, underline, strikethrough, two heading levels, body text, bulleted and numbered lists, quote, code block, link, image, and clear formatting. Buttons light up to show what's active at the caret.
Drag and drop images straight into a note, or paste them from the clipboard, or pick them with
the image button. Images are written to an attachments folder beside the database and referenced
through a private monki:// URL scheme rather than being inlined as base64, so the database stays
small and syncs quickly.
Notes autosave 400 ms after you stop typing, and any pending edit is flushed before you switch notes — there is no save button and nothing to lose.
Every note is indexed with SQLite FTS5 over a tag-stripped copy of its text, so results match prose rather than markup. Press ⌘F / Ctrl+F and results appear as you type, ranked by BM25, each showing its folder path and a matching snippet. Picking a result expands every column along its path to reveal it.
Two explicit themes, switched in Settings → Appearance. The app deliberately does not follow the system appearance — the theme is your choice and it sticks. The palette is entirely neutral: greys, white, and near-black, with no brand colour anywhere in the UI. The focused folder or note is marked with a white selection chip.
Five columns of hierarchy and a rich text note, side by side:
The same window in light mode — the theme is an explicit choice, not the system's:
Settings: theme, editor text size, and your own Google Drive credentials:
curl -fsSL https://raw.githubusercontent.com/mishenThakshana/monkiNotes/main/install.sh | bashPicks the right build for Apple silicon or Intel, installs it to /Applications and opens it.
Use this rather than the .dmg: curl downloads are not quarantined by macOS, so the app just
launches — no security dialog and nothing to click through.
Grab the installer for your platform from the Releases page:
| Platform | File |
|---|---|
| macOS (Apple silicon & Intel) | MonkiNotes-<version>-<arch>.dmg |
| Windows | MonkiNotes Setup <version>.exe (or the portable .exe) |
| Linux | .AppImage, .deb, or .rpm |
macOS: prefer the one-line installer above. If you take the
.dmgfrom a browser instead, macOS quarantines it and — because the build is unsigned — reports it as "MonkiNotes is damaged and can't be opened". The app is fine; clear the flag once after moving it to Applications:xattr -dr com.apple.quarantine /Applications/MonkiNotes.appRight-click → Open does not clear this particular dialog; the command above is the fix.
git clone https://github.com/mishenThakshana/monkiNotes.git
cd monkiNotes
npm install # also rebuilds better-sqlite3 against Electron's ABI
npm run dev # hot-reloading development appRequires Node.js 20+. On Linux you'll need the usual native build toolchain
(build-essential, python3) for better-sqlite3.
| Action | macOS | Windows / Linux |
|---|---|---|
| New note / folder | right-click any column, or ⌘N / ⇧⌘N | right-click, or Ctrl+N / Ctrl+Shift+N |
| Search all notes | ⌘F | Ctrl+F |
| Rename selection | Enter | Enter |
| Delete selection | ⌫ | Delete |
| Go up a level | ← | ← |
| Bold / italic / underline | ⌘B ⌘I ⌘U | Ctrl+B Ctrl+I Ctrl+U |
| Export note as HTML | ⇧⌘E | Ctrl+Shift+E |
| Sync now | ⌘S | Ctrl+S |
| Settings | ⌘, | Ctrl+, |
Sync is off until you turn it on, and MonkiNotes deliberately ships without an embedded Google client — an OAuth secret in a public repository is not a secret. You create a client in your own Google Cloud project, which means the app talks to Google as you, and your notes never touch infrastructure belonging to this project.
- Open the Google Cloud Console and create a project.
- APIs & Services → Library → Google Drive API → Enable.
- OAuth consent screen → External → add your own Google account as a test user.
The only scope needed is
drive.appdata, which is non-sensitive. - Credentials → Create credentials → OAuth client ID → Desktop app.
- In MonkiNotes: Settings → Google Drive sync, paste the client ID and secret, then Connect Google Drive. Your browser opens for consent and hands the app back a token.
- Sign-in uses the OAuth 2.0 loopback flow with PKCE. The redirect lands on a short-lived
127.0.0.1listener; the authorisation code is bound to a one-time verifier. - The refresh token is encrypted with Electron's
safeStorage, which is backed by the macOS Keychain, Windows DPAPI, or your Linux keyring. - The database is snapshotted into Drive's
appDataFolder— a hidden per-app folder. It does not appear in your Drive, and no other app (including anything else you build) can read it. - Each side carries a revision stamp. On sync the newer revision wins: newer locally pushes, newer remotely pulls and reloads the open window. Auto-sync runs every 5 minutes when enabled.
- Revoking access is one click (Disconnect), which also revokes the token at Google.
Important
Reconciliation is snapshot-level, not per-note. If you edit on two machines while both are offline, the machine that syncs second wins for the whole database — concurrent edits are not merged. Sync is designed as a reliable backup and a good hand-off between devices you use one at a time, not as multi-writer collaboration.
Note
Only the database is synced. Images live alongside it in attachments/ and are not uploaded,
so a note pulled onto a second machine will show its text but not its pictures.
| Platform | Path |
|---|---|
| macOS | ~/Library/Application Support/monki-notes/ |
| Windows | %APPDATA%\monki-notes\ |
| Linux | ~/.config/monki-notes/ |
That folder holds monki-notes.db — an ordinary SQLite file you can open with any SQLite client —
and an attachments/ directory of images. Settings → Show database file reveals it in your
file manager.
src/
├── main/ Electron main process (Node)
│ ├── index.ts window creation, lifecycle, single-instance lock
│ ├── db.ts SQLite schema, tree queries, FTS5 index
│ ├── attachments.ts image storage + the privileged monki:// scheme
│ ├── drive.ts Google OAuth + Drive REST, no SDK dependency
│ ├── sync.ts reconciliation, auto-sync timer, status broadcast
│ ├── ipc.ts the whole main↔renderer contract
│ └── menu.ts native application menu
├── preload/ contextBridge surface — the only API the UI can reach
├── renderer/ React UI (column browser, rich editor, search, settings)
└── shared/ dependency-free types used by all three
Security posture. nodeIntegration is off and contextIsolation is on; the renderer's entire
capability set is the explicit allowlist in src/preload/index.ts. A CSP forbids remote code and
remote images. Note bodies are HTML, so they pass through a whitelist sanitiser on load and on
paste — unknown elements are unwrapped rather than dropped, javascript: URLs are stripped, and an
<img> may only point at an attachment or a data: image. External links are handed to the system
browser rather than opened in-app, and the app is a single instance so one process owns the database.
Data model. Folders and notes are rows in one nodes table with a self-referencing
parent_id. Depth is therefore unbounded and free: paths, subtree deletion, and cycle checks are
recursive CTEs rather than application loops. Ordering uses a sparse REAL position so a
reorder is a single row update instead of a renumbering pass. A plain column mirrors the HTML as
text purely so FTS5 indexes words instead of tags.
npm run dev # development app with HMR
npm run typecheck # tsc over main, preload and renderer
npm run build # typecheck + production bundle into out/
npm run dist # installers for the current platform, into release/
npm run dist:mac # or :win / :linux
npm run icons # regenerate icon.icns / icon.ico from build/icon.png (macOS only)Cross-platform installers are best produced on their own platform. better-sqlite3 is native, so
electron-builder rebuilds it per target; on Windows/Linux it can't be built from a Mac without a
container. Pushing a v* tag runs the release workflow, which
builds all three platforms and attaches the installers to the GitHub release.
Tip
npm run dist:mac also builds the Intel target, which leaves better-sqlite3 compiled for x64
and makes npm run dev fail with an "incompatible architecture" error on Apple silicon. Run
npm run postinstall to rebuild it for your own machine.
Unsigned builds work everywhere but need the quarantine workaround above on macOS. To sign, set
the standard electron-builder environment variables before npm run dist:
- macOS —
CSC_LINK,CSC_KEY_PASSWORD, plusAPPLE_ID,APPLE_APP_SPECIFIC_PASSWORD,APPLE_TEAM_IDfor notarisation. Hardened runtime, entitlements andnotarize: trueare already configured; signing requires a paid Apple Developer Program membership. - Windows —
CSC_LINKandCSC_KEY_PASSWORD.
Releases sign themselves once these repository secrets exist — MAC_CSC_LINK,
MAC_CSC_KEY_PASSWORD, APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, APPLE_TEAM_ID. Without
them the workflow keeps producing unsigned artifacts.
MonkiNotes is not trying to replace a knowledge base or a team wiki. It is aimed at people who want a fast local notes app with real folders and nothing else attached.
| MonkiNotes | Typical cloud notes app | |
|---|---|---|
| Account required | No | Usually yes |
| Works fully offline | Yes, always | Partially |
| Where notes live | One SQLite file you own | Vendor's servers |
| Folder nesting | Unlimited, column browser | Often 2–3 levels |
| Sync | Optional, your own Google credentials | Mandatory, vendor-run |
| Telemetry | None | Common |
| Price | Free, MIT licensed | Free tier + subscription |
Is MonkiNotes free? Yes — free and open source under the MIT licence, for personal and commercial use.
Does it work offline? Always. Everything is local by default; sync is an optional extra you switch on yourself.
Where are my notes stored? In a single SQLite database in your user data folder (see Where your data lives). You can open it with any SQLite client, back it up, or copy it to another machine.
Do I need a Google account? No. Google Drive sync is entirely optional and off by default.
Can I nest folders more than a few levels deep? Yes — there is no depth limit. The column browser shows five columns at a time and slides as you go deeper, so a ten-level hierarchy stays readable.
Does it support Markdown? The editor is rich text (WYSIWYG) rather than Markdown, with a formatting toolbar. Notes export as HTML.
Which platforms are supported? macOS (Apple silicon and Intel), Windows, and Linux (AppImage, deb, rpm).
Is it a Notion / Evernote / Apple Notes replacement? Only if what you want from them is fast local notes in deep folders. There are no databases, backlinks, collaboration, or web clipper.
Issues and pull requests are welcome. Please run npm run typecheck before opening a PR, and keep
the dependency list short — staying lightweight is the point of this project.


