The Problem

Developers need a single UI that can connect to any SQL/NoSQL database without the overhead of installing a heavyweight tool like pgAdmin. Switching between Postgres, MySQL, MongoDB, Redis, or SQLite requires separate clients, each with its own quirks, which slows debugging and schema exploration.

What This Does

db-studio is a self‑hosted, cross‑database management UI built on React 19 (frontend) and a Hono‑based Node server (backend). The repository is a monorepo split into three logical packages:

  • packages/server – the API layer that talks to the selected database driver (mongo.adapter.ts, pg.adapter.ts, etc.) and exposes REST endpoints (routes/*.routes.ts).
  • packages/ui – the React component library (primitives/button.tsx, utils.ts) that renders tables, query editors, and connection dialogs.
  • packages/proxy – a Cloudflare‑Workers proxy (src/index.ts) used when the app is deployed behind a CDN.

The UI imports shared type definitions from packages/shared/src/types/database.types.ts (13 dependents) and utility helpers from packages/ui/src/utils.ts (35 dependents), making those modules the highest‑impact “hub” points in the codebase.

How It Is Wired

  1. CLI entrynpx db-studio invokes the binary defined in the root package.json. That binary loads packages/server/src/cmd/args.ts, parses CLI flags (--env, --database-url, etc.), and then calls packages/server/src/cmd/load-env.ts to locate a .env file.
  2. Server bootstrappackages/server/src/index.ts creates a Hono app via utils/create-server.ts. Middleware middlewares/error-handler.ts is attached, then each route file (routes/*.routes.ts) registers its endpoints.
  3. Database adapters – Each route handler delegates to an adapter (src/adapters/*/*.adapter.ts). For example, routes/tables.routes.ts ultimately calls packages/server/src/dao/mongo/table-list.mongo.dao.ts, which uses mongo.utils.ts for connection handling. The adapters share the packages/shared/src/types/* definitions.
  4. Proxy (optional) – When deployed to Cloudflare, packages/proxy/src/index.ts spins up a worker that forwards API calls to the server, applying rate limits from shared/constants/proxy-limits.ts.
  5. Frontend startup – The UI bundle is produced by Vite (see package.json scripts). The entry point packages/ui/src/index.ts re‑exports components; the router (react-router) loads feature modules such as features/tables/components/table-header.tsx. The most connected UI file is packages/ui/src/utils.ts, which is imported by 35 other UI modules, so any change there ripples widely.

Circular import cycles appear in the query‑runner UI (runner-screen.tsxrunner-header.tsxwww/src/routeTree.gen.ts), increasing the risk of runtime undefined errors if a module’s export shape changes.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/db-studio
cd db-studio

# Install dependencies with Bun (preferred) or npm
bun install   # reads bun.lock & bunfig.toml
# or npm ci   # note: no lockfile is present, builds are non‑reproducible

# Create a .env in the project root (or any parent) with:
# DATABASE_URL=postgresql://user:pass@host:5432/dbname

# Run the UI locally
npx db-studio           # uses default port 3333
# Or override flags:
npx db-studio --port 4000 --env .env.local

The server starts on the chosen port, reads the connection string, and serves the React UI at http://localhost:<port>. No additional build step is required because Vite runs in dev mode when launched via the binary.

Real‑World Use

A SaaS platform can embed db-studio in its admin console to let support engineers inspect a customer's PostgreSQL or MongoDB instance without leaving the internal dashboard. The platform would set DATABASE_URL dynamically per tenant, start the binary as a child process, and proxy the UI through the same domain, relying on the shared type definitions to keep client‑side and server‑side schemas consistent.

Code Health & Issues

Measured findings (static analysis)

  • HIGH – Hub module: packages/ui/src/utils.ts, packages/shared/src/types/database.types.ts, packages/ui/src/primitives/button.tsx each have >30 dependents → high blast radius.
  • HIGH – Deep nesting: 49 files (e.g., packages/web/src/shared/api/client.ts) contain indentation depth ≥ 8, making logic hard to follow.
  • MEDIUM – High branching density: packages/server/src/dao/mongo/mongo.utils.ts has 52 branches in 168 lines.
  • HIGH – Duplicated code: 1 365 repeated 6‑line blocks across 146 files (adapter layer).
  • HIGH – Import cycle: packages/web/src/features/query-runner/screens/runner-screen.tsxrunner-header.tsxwww/src/routeTree.gen.ts.
  • HIGH – Oversized file: packages/web/src/features/tables/components/table-cell-variant.tsx (1 204 lines).
  • MEDIUM – Empty catch: packages/web/src/routes/__root.tsx silently discards errors.

Code‑health audit

  • HIGH – Pin GitHub Action versions to commit SHAs (.github/workflows/*).
  • MEDIUM – Declare least‑privilege GITHUB_TOKEN permissions (.github/workflows/check.yml).
  • MEDIUM – Add a dependency‑vulnerability scan to CI.
  • LOW – Set timeout-minutes on workflow jobs.
  • LOW – Add missing convention files (.editorconfig, .gitattributes, formatter config).

Additional observations: the repo lacks a lockfile, so builds are non‑reproducible; tests exist (51 files) and CI runs via GitHub Actions; no Dockerfile is provided, so containerisation must be added manually if required.

The Bottom Line

db-studio delivers a functional, single‑pane UI for many databases with a clear separation of concerns between adapters, shared types, and the React front‑end. The codebase is actively tested but suffers from high‑impact hub modules, duplicated adapter logic, and a few architectural smells (deep nesting, import cycles). It is suitable for teams that need a quick, extensible admin UI and are comfortable addressing the identified hotspots before scaling in production.