Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dbviewer

A beautiful, local database client. Postico-inspired, runs in your browser. Supports PostgreSQL and MySQL, with SSH tunneling and a real SQL editor.

Quick start

cd dbviewer
npm install
npm start

Open http://127.0.0.1:5435.

Features

  • PostgreSQL and MySQL — pick the driver per connection. The SQL editor auto-switches dialect.
  • SSH tunneling — connect to databases behind a bastion, with private-key (passphrase optional) or password auth. Tunnel is opened lazily and torn down on disconnect.
  • CodeMirror SQL editor — line numbers, syntax highlighting, ⌘↵ to run, autocomplete (Ctrl-Space, auto-trigger after .) seeded with the live schema.
  • Query history — last 50 queries per connection persisted in SQLite; click an entry to load it back into the editor.
  • macOS Keychain — opt-in per-connection password storage (keytarSecItemAdd). Default on for new connections.
  • Connections sidebar with environment color tags (dev / staging / prod / local).
  • Schema tree — click a schema to expand, click a table to open it.
  • Content tab — paginated rows (100 per page), striped grid, type badges in column headers.
  • Structure tab — column list with type, nullability, default.
  • SQL tab — transactional execution, query timing, 1,000-row safety cap.
  • Read-only mode — wraps each SQL execution in BEGIN READ ONLY (Postgres) / START TRANSACTION READ ONLY (MySQL). Recommended for prod.

Security model

  • Localhost-only: server binds to 127.0.0.1 (not 0.0.0.0).
  • Host-header allowlist: rejects requests where Host isn't localhost / 127.0.0.1 / [::1] (DNS rebinding guard).
  • Cookie-based CSRF: every state-changing request must echo the CSRF cookie via X-CSRF-Token.
  • No password persistence: connection metadata (host, user, db, SSH host/user/key path) lives at ~/.dbviewer/connections.json with mode 0600. Passwords and SSH passphrases are entered each session and held only in memory; they're discarded when the process exits.
  • Server-enforced read-only: queries run inside a transaction so writes can't slip through and errors roll back cleanly.
  • Statement timeout: 30s per query (Postgres). Result row cap: 1,000.
  • Identifier validation: the table-rows endpoint rejects schema/table names that aren't plain identifiers, so the only place raw SQL touches the wire is the SQL tab itself.
  • CSP: default-src 'self' with no remote scripts; CodeMirror is bundled locally and served from /cm.

SSH tunneling

When SSH is enabled on a connection:

  1. dbviewer opens an SSH client to your bastion.
  2. It starts a local TCP listener on 127.0.0.1:<random>.
  3. Each driver connection through that listener is forwarded over the SSH session to the actual database host.
  4. On disconnect, the listener and SSH client are both torn down.

You can use either a private key (path; ~ is expanded) or a password. Key passphrase is asked at connect time.

File layout

dbviewer/
├── server.js                 Express server + API
├── lib/
│   ├── db.js                 SQLite (state.db) wrapper + schema migration
│   ├── store.js              Connection metadata (CRUD on connections table)
│   ├── history.js            Per-connection query history (last 50)
│   ├── pool.js               Per-session driver/tunnel registry
│   ├── ssh.js                ssh2 tunnel helper
│   ├── keychain.js           macOS Keychain wrapper (keytar)
│   └── drivers/
│       ├── index.js          Driver factory
│       ├── postgres.js       pg driver implementation
│       └── mysql.js          mysql2 driver implementation
├── public/
│   ├── index.html            App shell (loads CodeMirror from /cm)
│   ├── styles.css            Theme & components
│   └── app.js                Frontend logic
└── package.json

State on disk

Stored under ~/.dbviewer/ (mode 0700):

File Contents
state.db SQLite — connections and query_history tables
state.db-shm, state.db-wal SQLite WAL journal (auto-managed)
connections.json.migrated-<ts> One-shot backup from the legacy JSON store on first SQLite boot

Passwords are not in state.db — they live in the macOS Keychain (when "Save password to Keychain" is enabled on the connection) or in process memory only.

Keyboard shortcuts

Shortcut Action
⌘N / Ctrl+N New connection
⌘↵ / Ctrl+Enter Run SQL query (when editor is focused)
Esc Close modal

Configuration

Variable Default Effect
PORT 5435 Port the server listens on

Notes & limitations

  • Result grid is non-virtualized; the 1,000-row cap keeps things responsive.
  • MySQL SHOW DATABASES is shown as the schema tree (system schemas filtered).
  • Statement timeout is enforced server-side for Postgres only; MySQL doesn't support per-pool statement_timeout. Use SET SESSION MAX_EXECUTION_TIME in a query if needed.

License

MIT — see LICENSE.

About

A beautiful, local PostgreSQL/MySQL client. Postico-inspired, browser-based.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages