Back to Articles

Laverna: Building a Zero-Knowledge Note App with Client-Side Encryption

[ View on GitHub ]

Laverna: Building a Zero-Knowledge Note App with Client-Side Encryption

Hook

While Evernote can technically read every note you've ever written, Laverna's architecture makes it mathematically impossible for anyone—including the developers—to decrypt your data. That's not marketing; that's cryptography.

Context

When Laverna emerged in 2013, the post-Snowden era had developers questioning centralized services that held unencrypted user data. Evernote, OneNote, and Google Keep all stored notes on their servers in formats they could read, analyze, and potentially hand over to authorities. The note-taking market needed an answer to a fundamental question: Could you build a fully-featured note application where the service provider has zero knowledge of user content?

Laverna's answer was radical simplicity: move everything to the client. No user accounts, no server-side storage, no backend APIs processing your thoughts. Instead, notes live encrypted in your browser's IndexedDB, synced peer-to-peer when needed, and backed up to storage you control. It's an architecture that trades the convenience of centralized services for the certainty of data sovereignty. The project attracted over 9,000 GitHub stars by showing developers exactly how to build privacy into the foundation rather than bolting it on later.

Technical Insight

Client-Side Only

Raw note data

Encrypt with AES

Store encrypted

Retrieve encrypted

Decrypt

Plaintext

Optional P2P sync

Encrypted data only

Marionette.js UI Layer

Pagedown Markdown Editor

SJCL Encryption Module

Backbone Sync Adapter

IndexedDB/localStorage

Dropbox/RemoteStorage Sync

System architecture — auto-generated

Laverna's architecture revolves around three core principles: client-side encryption, offline-first data storage, and optional peer-to-peer synchronization. Let's examine how each piece works and why these decisions matter.

The encryption layer uses the Stanford JavaScript Crypto Library (SJCL) to implement AES encryption before any data touches storage. When you create a note, Laverna generates an encryption key from your passphrase using PBKDF2 with configurable iterations. This happens entirely in-browser JavaScript—no key material ever leaves your machine. Here's the essential flow from the codebase:

// Simplified encryption flow from Laverna's crypto module
encrypt: function(data, password) {
    // Derive key from password using PBKDF2
    var key = sjcl.misc.pbkdf2(password, this.salt, this.iter);
    
    // Convert data to JSON and encrypt with AES
    var encrypted = sjcl.encrypt(key, JSON.stringify(data), {
        mode: 'ccm',
        ts: 128,
        ks: 256,
        iter: 10000
    });
    
    return encrypted;
}

This approach means Laverna can't implement server-side search, can't offer password recovery, and can't help if you forget your passphrase. Those aren't bugs—they're proof the encryption is real. The moment a service can recover your password, they can read your data.

The storage layer uses a Backbone.js-based abstraction that writes to IndexedDB (with localStorage fallback) through a custom sync adapter. Laverna implements a complete CRUD interface that feels like working with a remote API, except everything happens locally. The database schema organizes notes, notebooks, tags, and files into separate object stores, each encrypted independently. This granular encryption means you can share individual notes without exposing your entire database.

For synchronization, Laverna takes an unusual approach: it doesn't build its own sync server. Instead, it integrates with Dropbox and RemoteStorage as dumb file storage. The sync module encrypts your entire database, serializes it to JSON, and uploads it as an opaque blob. When syncing from another device, it downloads, decrypts, and merges changes using a basic last-write-wins strategy:

// Sync conflict resolution
resolveConflict: function(local, remote) {
    // Compare timestamps
    if (local.updated > remote.updated) {
        return local;
    } else if (remote.updated > local.updated) {
        return remote;
    }
    
    // If timestamps match, prefer longer content
    return local.content.length >= remote.content.length ? local : remote;
}

This conflict resolution is naive—it can lose edits if you modify the same note on two devices between syncs. But it's predictable and doesn't require a central authority to arbitrate conflicts. For many users, that trade-off is acceptable.

The peer-to-peer capabilities use WebRTC for direct browser-to-browser connections, with Socket.IO handling signaling. This lets you share notes directly between devices without uploading to any cloud service. The implementation creates a temporary encrypted channel using the Web Crypto API, exchanges note data as encrypted JSON blobs, and closes the connection. It's ephemeral by design—no persistent peer network, no DHT, just point-to-point transfers when you need them.

Laverna's Markdown editor integrates Pagedown, the same library that powered Stack Overflow's editor for years. It provides live preview, syntax highlighting, and inline image support. The editor component is relatively straightforward Marionette.js view code, but the architecture ensures every keystroke is immediately persisted to IndexedDB (encrypted) and debounced to avoid thrashing the database.

The build system uses Gulp.js to concatenate and minify JavaScript, compile LESS stylesheets, and bundle everything into a single-page application. For desktop distribution, the codebase includes Electron wrapper configuration that packages the web app as a native application with file system access and system tray integration. This multi-target approach—web, desktop, self-hosted—gives users genuine choice in how they deploy the tool.

Gotcha

The elephant in the room: Laverna appears unmaintained. The last significant commit was years ago, the dependencies are ancient (Bower was effectively deprecated in 2017), and the framework stack (Marionette.js, Backbone.js) represents mid-2010s JavaScript architecture. This isn't just aesthetic—it means security vulnerabilities in dependencies won't be patched, compatibility with modern browsers may break, and features users expect (mobile apps, modern sync protocols, collaborative editing) will never arrive.

The technical limitations are equally significant. The conflict resolution strategy can silently lose data if you edit the same note offline on multiple devices. The encryption, while sound, uses configurable iteration counts that default to 1,000—modern recommendations suggest at least 100,000 for PBKDF2. The peer-to-peer sync requires both devices online simultaneously with working NAT traversal, which fails more often than you'd hope. And perhaps most critically for a note-taking app: there's no official mobile client. In 2024, a note app without first-class mobile support is like a car without air conditioning—technically functional but practically limiting.

Verdict

Use Laverna if you're building your own privacy-focused note application and need a reference implementation showing client-side encryption, offline-first architecture, and zero-knowledge principles in action. It's excellent educational material for understanding how to structure encrypted web apps. Also consider it if you need a simple, self-hosted note tool right now, understand JavaScript well enough to patch issues yourself, and primarily work on desktop. Skip if you need active maintenance, mobile apps, robust multi-device sync, or modern development experience. For production use, look at actively maintained alternatives like Standard Notes or Joplin that implement similar privacy principles with contemporary tooling. Laverna's real legacy isn't the tool itself—it's proving that zero-knowledge note-taking was architecturally possible, inspiring the generation of privacy-focused apps that followed.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/ai-dev-tools/laverna-laverna.svg)](https://starlog.is/api/badge-click/ai-dev-tools/laverna-laverna)