Shubham Upadhyay

Senior Backend Architect

Open to Collaborate
Bengaluru, IN
Connect Channels
Go & Linux Systems 5 min read Dec 2023 ClipNest

Why I Skipped Electron: Building a 14MB Native Clipboard Manager in Go

How pairing a quiet Wayland background daemon with an embedded local web UI replaced a 400MB memory hog.

Shubham Upadhyay

Shubham Upadhyay

Senior Backend & Systems Engineer

01.

The Electron Tax: Why Does a Clipboard Tool Need 400 MB of RAM?

Every developer running a modern Linux desktop has encountered the same frustration. You want a simple, reliable clipboard history tool so you don't lose snippets, shell commands, or URLs when jumping between windows. You browse GitHub or your package manager, install a popular utility, and check htop five minutes later.

The tool has spawned four separate helper processes, opened three Chromium renderer threads, and is quietly consuming 420 MB of resident memory.

For an application whose entire job is listening to clipboard events and storing small strings in a table, burning nearly half a gigabyte of memory feels absurd. When you're running IDEs, Docker containers, local test databases, and browser tabs, your background utilities shouldn't be competing for system resources.

Even worse is what happens when you switch to a modern Linux Wayland desktop (GNOME, Sway, Hyprland). Most older clipboard tools rely on X11 hooks that silently stop working or crash when the display server restricts global window snooping. And nearly all of them have a critical privacy flaw: they blindly record everything you copy, including master passwords from Bitwarden or production tokens from 1Password.

I decided to build ClipNest to fix all three issues: a native Go daemon that sips ~14 MB of RAM, integrates cleanly with Wayland, pauses recording when copying secrets, and serves a crisp local web UI without bundling Chromium.

"A clipboard manager shouldn't consume more memory than the code editor you're working in, and it should never log your passwords without asking."

— Shubham Upadhyay
02.

The Trade-Off: Electron Wrapper vs. Native Go Daemon

When building modern desktop utilities, wrapping a web frontend in Electron or Chromium is the easiest shortcut. But comparing the runtime footprint, startup latency, and battery impact reveals why a compiled Go binary is the superior choice for an always-on background daemon.

The Electron Approach (Chromium + Node.js)

  • Bundles an entire Chromium browser engine and Node.js runtime, ballooning installer downloads to 120MB+.
  • Consumes 350 MB to 500 MB of resident memory (RSS) just sitting idle in the system tray waiting for copy events.
  • Requires heavy npm dependency trees with hundreds of third-party packages and constant security update churn.
  • Spawns multiple renderer, GPU, and worker processes that cause frequent CPU wakeups and drain laptop battery.
  • Often relies on legacy X11 clipboard APIs that fail silently or crash on modern Linux Wayland compositors.

The ClipNest Approach (Compiled Go + Embedded UI)

  • Compiles into a single self-contained binary (~16 MB) with zero runtime dependencies or external runtimes required.
  • Consumes only ~14 MB of RAM at idle while continuously monitoring the system clipboard in the background.
  • Uses Go's embed package to compile HTML, CSS, JavaScript, and glassmorphism assets directly into the binary.
  • Runs quietly as a standard systemd user service with near-zero CPU wakeups and instant sub-20ms cold startup.
  • First-class Linux Wayland support via wl-clipboard event streaming with clean handling of text and image buffers.
03.

The Wayland Challenge: Listening to Events in a Secure Window System

Under legacy X11, any application could register a global event listener and read whatever was on the clipboard at any moment. While that made writing clipboard managers trivial, it was a massive security vulnerability: any untrusted script or compromised utility could silently snoop on every piece of data you copied.

Wayland deliberately abolished this model. In a Wayland compositor (like Hyprland, Sway, or GNOME Shell), client applications are isolated. A window cannot inspect keystrokes or clipboard contents belonging to another application unless explicitly mediated by the compositor.

To capture clipboard updates reliably without fighting Wayland's security boundaries, ClipNest hooks into the standard wl-clipboard subsystem. It launches a dedicated streaming listener using wl-paste --watch, capturing newly copied MIME types as soon as the active window publishes them.

When a user clicks a snippet to restore in ClipNest's web UI, ClipNest pipes the payload directly into wl-copy, updating the compositor's active clipboard register in less than a millisecond.

internal/clipboard/wayland.go
Wayland Stream Listener
// Watch monitors the Wayland clipboard via wl-paste stream
func (w *WaylandBackend) Watch(ctx context.Context, onClip func(item ClipItem)) error {
    cmd := exec.CommandContext(ctx, "wl-paste", "--watch", "clipnest-hook")
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        return fmt.Errorf("failed to hook wl-paste: %w", err)
    }

    if err := cmd.Start(); err != nil {
        return fmt.Errorf("wl-clipboard daemon failed to start: %w", err)
    }

    scanner := bufio.NewScanner(stdout)
    for scanner.Scan() {
        text := scanner.Text()
        if w.privacy.IsPaused() || strings.TrimSpace(text) == "" {
            continue // Skip recording if privacy pause is active
        }

        onClip(ClipItem{
            Content:   text,
            MimeType:  "text/plain",
            CreatedAt: time.Now(),
        })
    }
    return cmd.Wait()
}
04.

Stop Logging My Passwords: Built-In Privacy & Local Persistence

Most clipboard managers act like indiscriminate hoovers—they capture every password, temporary one-time password (OTP), and SSH private key you copy. ClipNest was architected around privacy from day one.

Instant Privacy Pause Toggle

  • Includes an instant global pause toggle accessible via keyboard shortcut or the web dashboard with a single click.
  • Backed by a thread-safe sync.RWMutex: when paused, incoming clipboard stream events are discarded immediately in memory.
  • Zero plaintext leakage: copied passwords from Bitwarden, 1Password, or KeePass never touch the SQLite database or disk.
  • Visual status indicator in the UI immediately shows whether recording is active or suspended with real-time feedback.

Automatic SQLite Auto-Pruning

  • Background cleaner runs periodically to prevent the SQLite database (~/.local/share/clipnest/clipnest.db) from growing unchecked.
  • Unpinned entries older than 30 days or exceeding the 100-item threshold are automatically purged in the background.
  • Starred and pinned snippets are marked with is_pinned = 1 and permanently protected from automated cleanup.
  • Supports image snippet caching (PNG/JPEG) up to a 25 MB ceiling to prevent disk bloat while retaining screenshots.
05.

How It Works: Daemon, SQLite Store, and the Go Embed UI

ClipNest eliminates external dependencies by packaging its entire runtime—system event listeners, SQLite persistence, and modern web frontend—into a single Go binary.

CLIPNEST EVENT LIFECYCLE & INTERFACE ARCHITECTURE
1 Wayland Event Loop → wl-paste stream detects clipboard changes across desktop apps
2 Privacy Guard Check → sync.RWMutex verifies whether recording is active or paused
3 SQLite Storage Layer → Persists text & image data in ~/.local/share/clipnest/clipnest.db
4 Go Embed HTTP Server → Serves glassmorphism dashboard on localhost:49049 with zero Node.js
5 One-Click Restore → Web UI triggers wl-copy to put chosen snippet back on clipboard
06.

Engineering Takeaways

Web UIs Don't Require Electron

By compiling frontend assets with Go's embed package and serving them over a local HTTP port, you get modern web styling and glassmorphism without the 400MB Chromium memory footprint.

Privacy Must Be an Architectural Invariant

A clipboard manager that logs master passwords is a security liability. Building a thread-safe pause toggle directly into the event stream ensures peace of mind.

Linux System Plumbing Still Matters

Understanding display server boundaries—like the difference between X11 global hooks and Wayland's mediated pipe model—is critical for building robust desktop tools.

Small Daemons Stay Alive Forever

When a utility uses ~14 MB of RAM and boots in 20 milliseconds, users never feel the urge to close it. True developer utilities should be invisible until needed.

Explore Further

Want to review the full ClipNest overview?

Check out technical architecture, problems faced, and complete tech stack.

View Project Overview
Chat on WhatsApp
Navigating...