DEV Community

Shubhesh Shukla
Shubhesh Shukla

Posted on Edited on

Why I Built a Database Client in Go Instead of Electron

Most mornings at work I had three database tools open. DataGrip for MySQL, a Redshift-compatible client, and the AWS console for DynamoDB. That's three windows, three sets of saved credentials, three different query histories, and about 1.5GB of RAM just to look at tables.

I built DB Connect to replace all three. It's a free desktop database IDE for MySQL, Amazon Redshift, and DynamoDB. The installed binary is 18MB. It opens in under two seconds. And it does not bundle Chromium.

This post covers the technical decisions behind it — what worked, what was painful, and what I would change.

The problem

If you work at a company that runs MySQL for transactional data, Redshift for analytics, and DynamoDB for high-throughput key-value access, you know the tool fragmentation problem. Every database client either:

  • Supports relational databases well but ignores DynamoDB entirely
  • Is built on Java and takes 15 seconds to show you a cursor
  • Costs $25/month per seat for features you use 10% of

I wanted one tool that could connect to all three, store credentials securely, and not make my laptop fan spin up just by existing in the dock.

Why not just use what exists

I tried everything. Here's an honest comparison:

Tool Price Install Size Startup Stack DynamoDB
DataGrip $25/mo ~800MB 10-30s Java/IntelliJ No
DBeaver Free (community) ~400MB 5-15s Java/Eclipse No
TablePlus $89 (license) ~80MB <3s Native Yes
DB Connect Free 18MB <2s Go + Wails Yes

DataGrip is genuinely excellent if you live in relational-only land and your company pays for JetBrains. But no DynamoDB, and the cold start time on a Monday morning is painful.

DBeaver is the community workhorse. It does a lot. It also runs on Eclipse, which means it does a lot slowly. No DynamoDB support in the free tier.

TablePlus is the closest to what I wanted — it's native, fast, and supports DynamoDB. But the DynamoDB experience is basic, it's not free, and I wanted features like EXPLAIN visualization and parameterized saved queries that it doesn't offer.

None of them solved my specific problem: a fast, lightweight, free tool that treats MySQL, Redshift, and DynamoDB as equal citizens.

The tech stack decision

The first question was Electron vs. something else. Electron is the safe choice — massive ecosystem, battle-tested, every tutorial on the internet. But Electron means bundling Chromium, which means:

  • 400MB+ installed size minimum
  • 150-300MB RAM just for the shell before your app does anything
  • A full browser process even though you're building a desktop app

I went with Wails instead. Wails uses the system's native WebView (WebKit on macOS, WebView2 on Windows) and a Go backend. The tradeoff is real: you lose some cross-browser consistency and the Chrome DevTools you're used to. But you gain a single compiled binary, native performance, and an 18MB install.

Go was a natural fit for the backend. Database drivers are mature in the Go ecosystem (database/sql, go-sql-driver/mysql, aws-sdk-go-v2). Goroutines make it trivial to run queries without blocking the UI — every query execution spawns a goroutine, and the frontend gets results via Wails' binding system. No thread pools to manage, no callback hell.

The frontend is React 18 with TypeScript. Nothing exotic. The interesting piece is Monaco — the same editor engine that powers VS Code — which gives you autocomplete, syntax highlighting, multi-cursor editing, and bracket matching without building any of that from scratch.

Architecture overview

+-----------------------------------+
|  React + TypeScript + Monaco      |  <- UI layer
|  (runs in system WebView)         |
+-----------------------------------+
|  Wails v2 bridge                  |  <- function bindings, events
+-----------------------------------+
|  Go backend                       |
|   +- Connection manager           |  <- pool management, SSH tunnels
|   +- Query executor               |  <- goroutine per query
|   +- Credential store             |  <- AES-256-GCM + OS keychain
|   +- DynamoDB client              |  <- scan/query/GetItem abstraction
+-----------------------------------+
Enter fullscreen mode Exit fullscreen mode

Wails generates TypeScript bindings from Go structs and methods automatically. You export a Go method, and it becomes callable from JavaScript. No REST API, no WebSocket protocol, no serialization layer to maintain. The Go backend owns all database connections, all encryption, and all credential storage. The frontend never touches raw connection strings or passwords.

One quirk worth mentioning: PostHog analytics are routed through the Go backend as a proxy. Wails' WebView doesn't let you make arbitrary cross-origin requests the way a normal browser tab would, so the Go layer handles the HTTP calls to PostHog's ingest endpoint. It's a small thing, but the kind of thing you don't discover until you're debugging why your analytics silently fail.

The DynamoDB challenge

Most database tools ignore DynamoDB because it doesn't speak SQL and its data model is genuinely different. You can't just bolt a SQL editor onto it.

DynamoDB has partition keys, sort keys, global secondary indexes, and a type system that includes String (S), Number (N), Binary (B), List (L), Map (M), String Set (SS), Number Set (NS), and Binary Set (BS). Building a query means specifying key conditions, optional filter expressions, selecting an index, and understanding the difference between a Query (which requires a partition key) and a Scan (which reads the entire table and should terrify you in production).

DB Connect has a visual query builder that handles all of this. You pick your table, choose Query or Scan or GetItem, select a GSI if needed, build filter expressions with a form-based UI, and see results with proper type annotations.

The type system was the hardest part. A single DynamoDB item can have nested Maps containing Lists containing Maps containing Number Sets. The frontend needs to render this recursively, and the Go backend needs to marshal and unmarshal it correctly through the AWS SDK. I spent more time on DynamoDB type handling than on the entire MySQL integration.

Security decisions

Credentials are encrypted with AES-256-GCM before being stored. The encryption key lives in the OS keychain — macOS Keychain on Mac, Windows Credential Manager on Windows. Your database passwords never exist as plaintext on disk.

This matters more than people think. I've seen popular database tools that store passwords in plaintext JSON files or use reversible encoding that any script can decode. If someone gets read access to your home directory — through a compromised dependency, a shared machine, or a backup that wasn't encrypted — they get every database credential you have saved.

SSH tunnel support is built in for MySQL connections. You configure the tunnel parameters alongside your connection details, and the Go backend establishes the tunnel before connecting to MySQL through it.

Performance tricks

Three things keep DB Connect fast with large data:

Virtual scrolling. Result sets render using virtualized rows. Only the visible rows plus a small buffer exist in the DOM at any time. You can scroll through hundreds of thousands of rows without the browser choking on DOM nodes.

Goroutine-per-query. Every query execution runs in its own goroutine. The Wails event system pushes results back to the frontend when they're ready. Long-running Redshift analytics queries don't freeze the UI — you can switch tabs and run a quick MySQL lookup while waiting.

Binary size optimization. Go 1.25 with Wails produces a single binary. No JVM, no Node runtime, no native module compilation. The universal macOS build (Intel + Apple Silicon in one binary) is still under 20MB.

What I would do differently

Wails' WebView inconsistencies are real. WebKit on macOS and WebView2 on Windows don't behave identically. CSS that works perfectly on one platform occasionally needs tweaks for the other. I'd still choose Wails for the size and performance benefits, but budget time for platform-specific testing.

I underestimated the DynamoDB type system. I thought it would be a weekend project to add DynamoDB support. It took weeks. If I were starting over, I'd prototype the DynamoDB UI first since it was the riskiest piece.

Monaco is powerful but heavy for a WebView. Monaco is around 2-3MB of JavaScript. In a WebView-based app where you're optimizing for fast startup, it's noticeable. It's still worth it — rebuilding a code editor from scratch would be absurd — but I explored lighter alternatives before accepting the tradeoff.

What's next

  • PostgreSQL support — the most requested feature
  • MongoDB support — another NoSQL engine that most SQL-focused tools handle poorly
  • Linux builds — Wails supports Linux, I just need to set up the CI pipeline
  • ER diagram visualization — auto-generated from foreign key relationships
  • Query plan diff — compare EXPLAIN output before and after index changes

Try it out

DB Connect is free. I built it for my own workflow and am releasing it because the database tool space shouldn't require a subscription or a gigabyte of disk space for basic functionality.

If you work with MySQL, Redshift, or DynamoDB and are tired of juggling multiple tools, give it a shot. Issues and feature requests are welcome.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.