<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shubhesh Shukla</title>
    <description>The latest articles on DEV Community by Shubhesh Shukla (@shubhesh07).</description>
    <link>https://dev.to/shubhesh07</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3910806%2Fcf67c9a9-fb07-4542-af3a-21bb1875e150.png</url>
      <title>DEV Community: Shubhesh Shukla</title>
      <link>https://dev.to/shubhesh07</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shubhesh07"/>
    <language>en</language>
    <item>
      <title>Why I Built a Database Client in Go Instead of Electron</title>
      <dc:creator>Shubhesh Shukla</dc:creator>
      <pubDate>Sun, 03 May 2026 18:55:33 +0000</pubDate>
      <link>https://dev.to/shubhesh07/why-i-built-a-database-client-in-go-instead-of-electron-cmd</link>
      <guid>https://dev.to/shubhesh07/why-i-built-a-database-client-in-go-instead-of-electron-cmd</guid>
      <description>&lt;p&gt;Most mornings at work I had three database tools open. DataGrip for MySQL, a Redshift-compatible client, and the AWS console for DynamoDB. That is three windows, three sets&lt;br&gt;
  of saved credentials, three different query histories, and about 1.5GB of RAM just to look at tables.                                                                         &lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://shubhesh07.github.io/db-connect/" rel="noopener noreferrer"&gt;https://shubhesh07.github.io/db-connect/&lt;/a&gt; to replace all three. It is a free desktop database IDE for MySQL, Amazon Redshift, and DynamoDB. The installed binary is&lt;br&gt;&lt;br&gt;
  18MB. It opens in under two seconds. And it does not bundle Chromium.                                                                                                         &lt;/p&gt;

&lt;p&gt;This post covers the technical decisions behind it — what worked, what was painful, and what I would change.                                                                  &lt;/p&gt;

&lt;p&gt;The problem&lt;/p&gt;

&lt;p&gt;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&lt;br&gt;&lt;br&gt;
  problem. Every database client either:&lt;/p&gt;

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

&lt;p&gt;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.                               &lt;/p&gt;

&lt;p&gt;Why not just use what exists                                                                                                                                                  &lt;/p&gt;

&lt;p&gt;I tried everything. Here is an honest comparison:&lt;/p&gt;

&lt;p&gt;┌────────────┬──────────────────┬──────────────┬─────────┬───────────────┬──────────┐&lt;br&gt;&lt;br&gt;
  │    Tool    │      Price       │ Install Size │ Startup │     Stack     │ DynamoDB │&lt;br&gt;
  ├────────────┼──────────────────┼──────────────┼─────────┼───────────────┼──────────┤&lt;br&gt;&lt;br&gt;
  │ DataGrip   │ $25/mo           │ ~800MB       │ 10-30s  │ Java/IntelliJ │ No       │&lt;br&gt;
  ├────────────┼──────────────────┼──────────────┼─────────┼───────────────┼──────────┤&lt;br&gt;
  │ DBeaver    │ Free (community) │ ~400MB       │ 5-15s   │ Java/Eclipse  │ No       │&lt;br&gt;
  ├────────────┼──────────────────┼──────────────┼─────────┼───────────────┼──────────┤&lt;br&gt;&lt;br&gt;
  │ TablePlus  │ $89 (license)    │ ~80MB        │ &amp;lt;3s     │ Native        │ Yes      │&lt;br&gt;
  ├────────────┼──────────────────┼──────────────┼─────────┼───────────────┼──────────┤&lt;br&gt;&lt;br&gt;
  │ DB Connect │ Free             │ 18MB         │ &amp;lt;2s     │ Go + Wails    │ Yes      │&lt;br&gt;
  └────────────┴──────────────────┴──────────────┴─────────┴───────────────┴──────────┘                                                                                         &lt;/p&gt;

&lt;p&gt;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&lt;br&gt;&lt;br&gt;
  painful.                                                  &lt;/p&gt;

&lt;p&gt;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.                           &lt;/p&gt;

&lt;p&gt;TablePlus is the closest to what I wanted — it is native, fast, and supports DynamoDB. But the DynamoDB experience is basic, it is not free, and I wanted features like&lt;br&gt;&lt;br&gt;
  EXPLAIN visualization and parameterized saved queries that it does not offer.&lt;/p&gt;

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

&lt;p&gt;The tech stack decision&lt;/p&gt;

&lt;p&gt;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&lt;br&gt;&lt;br&gt;
  bundling Chromium, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;400MB+ installed size minimum
&lt;/li&gt;
&lt;li&gt;150-300MB RAM just for the shell before your app does anything&lt;/li&gt;
&lt;li&gt;A full browser process even though you are building a desktop app
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I went with &lt;a href="https://wails.io" rel="noopener noreferrer"&gt;https://wails.io&lt;/a&gt; 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&lt;br&gt;&lt;br&gt;
  cross-browser consistency and the Chrome DevTools you are used to. But you gain a single compiled binary, native performance, and an 18MB install.&lt;/p&gt;

&lt;p&gt;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&lt;br&gt;&lt;br&gt;
  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&lt;br&gt;
  hell.                                                                                                                                                                         &lt;/p&gt;

&lt;p&gt;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 &lt;br&gt;
  highlighting, multi-cursor editing, and bracket matching without building any of that from scratch.&lt;/p&gt;

&lt;p&gt;Architecture overview                                     &lt;/p&gt;

&lt;p&gt;┌────────────────────��────────────┐&lt;br&gt;
  │  React + TypeScript + Monaco    │  ← UI layer&lt;br&gt;
  │  (runs in system WebView)       │&lt;br&gt;
  ��─────────────────────────────────┤&lt;br&gt;
  │  Wails v2 bridge                │  ← function bindings, events&lt;br&gt;&lt;br&gt;
  ├────��─────────────────���──────────┤&lt;br&gt;
  │  Go backend                     │&lt;br&gt;&lt;br&gt;
  │  ├── Connection manager         │  ← pool management, SSH tunnels&lt;br&gt;
  │  ├── Query executor             │  ← goroutine per query&lt;br&gt;
  │  ├── Credential store           │  ← AES-256-GCM + OS keychain&lt;br&gt;&lt;br&gt;
  │  ├─�� DynamoDB client            ���  ← scan/query/GetItem abstraction&lt;br&gt;
  │                                 │&lt;br&gt;&lt;br&gt;
  └─────────────────────────────────┘                                                                                                                                           &lt;/p&gt;

&lt;p&gt;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&lt;br&gt;&lt;br&gt;
  protocol, no serialization layer to maintain. The Go backend owns all database connections, all encryption, and all credential storage. The frontend never touches raw&lt;br&gt;
  connection strings or passwords.                                                                                                                                              &lt;/p&gt;

&lt;p&gt;One quirk worth mentioning: PostHog analytics are routed through the Go backend as a proxy. Wails' WebView does not let you make arbitrary cross-origin requests the way a&lt;br&gt;&lt;br&gt;
  normal browser tab would, so the Go layer handles the HTTP calls to PostHog's ingest endpoint. It is a small thing, but the kind of thing you do not discover until you are&lt;br&gt;
  debugging why your analytics silently fail.                                                                                                                                   &lt;/p&gt;

&lt;p&gt;The DynamoDB challenge&lt;/p&gt;

&lt;p&gt;Most database tools ignore DynamoDB because it does not speak SQL and its data model is genuinely different. You cannot just bolt a SQL editor onto it.&lt;/p&gt;

&lt;p&gt;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),&lt;br&gt;&lt;br&gt;
  Number Set (NS), and Binary Set (BS). Building a query means specifying key conditions, optional filter expressions, selecting an index, and understanding the difference&lt;br&gt;
  between a Query (which requires a partition key) and a Scan (which reads the entire table and should terrify you in production).                                              &lt;/p&gt;

&lt;p&gt;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 &lt;br&gt;
  form-based UI, and see results with proper type annotations.&lt;/p&gt;

&lt;p&gt;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&lt;br&gt;&lt;br&gt;
  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&lt;br&gt;
  integration.                                                                                                                                                                  &lt;/p&gt;

&lt;p&gt;Security decisions&lt;/p&gt;

&lt;p&gt;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.&lt;br&gt;&lt;br&gt;
  Your database passwords never exist as plaintext on disk.&lt;/p&gt;

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

&lt;p&gt;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 &lt;br&gt;
  connecting to MySQL through it.&lt;/p&gt;

&lt;p&gt;Performance tricks                                        &lt;/p&gt;

&lt;p&gt;Three things keep DB Connect fast with large data:&lt;/p&gt;

&lt;p&gt;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&lt;br&gt;&lt;br&gt;
  thousands of rows without the browser choking on DOM nodes.&lt;/p&gt;

&lt;p&gt;Goroutine-per-query. Every query execution runs in its own goroutine. The Wails event system pushes results back to the frontend when they are ready. Long-running Redshift&lt;br&gt;&lt;br&gt;
  analytics queries do not freeze the UI — you can switch tabs and run a quick MySQL lookup while waiting.&lt;/p&gt;

&lt;p&gt;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&lt;br&gt;
   in one binary) is still under 20MB.&lt;/p&gt;

&lt;p&gt;What I would do differently                               &lt;/p&gt;

&lt;p&gt;Wails' WebView inconsistencies are real. WebKit on macOS and WebView2 on Windows do not behave identically. CSS that works perfectly on one platform occasionally needs tweaks&lt;br&gt;
   for the other. I would still choose Wails for the size and performance benefits, but budget time for platform-specific testing.&lt;/p&gt;

&lt;p&gt;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 would prototype the&lt;br&gt;&lt;br&gt;
  DynamoDB UI first since it was the riskiest piece.&lt;/p&gt;

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

&lt;p&gt;What is next                                              &lt;/p&gt;

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

&lt;p&gt;Try it out&lt;/p&gt;

&lt;p&gt;DB Connect is free. I built it for my own workflow and am releasing it because the database tool space should not require a subscription or a gigabyte of disk space for basic&lt;br&gt;
   functionality.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download: &lt;a href="https://shubhesh07.github.io/db-connect/" rel="noopener noreferrer"&gt;https://shubhesh07.github.io/db-connect/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://github.com/shubhesh07/db-connect" rel="noopener noreferrer"&gt;https://github.com/shubhesh07/db-connect&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Runs on: macOS (Intel + Apple Silicon) and Windows
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.    &lt;/p&gt;

</description>
      <category>database</category>
      <category>go</category>
      <category>performance</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
