DEV Community

Ramananda Panda
Ramananda Panda

Posted on

I Built a Database Explorer That Can't Ruin Your Friday

Every developer has a database horror story.

Mine usually starts with a terminal, a production connection string,
and the words "quick fix". It ends with someone saying "so... do we
have backups?" in a very quiet voice.

So I built DBAdminer: a database explorer that starts in
read-only mode, because it assumes you're tired, caffeinated,
and one typo away from a postmortem.

What is it?

A database explorer for Go. Point it at PostgreSQL, MySQL,
MariaDB, or SQLite, open your browser, and poke around: tables,
data, a SQL console, the works.

Full access is there when you want it, but you have to ask for it.
Like the sudo of database tools.

Get it running in 30 seconds

Grab a binary from GitHub Releases (Linux, macOS, Windows,
amd64 and arm64), then:

dbadminer --dsn 'postgres://user:pass@127.0.0.1:5432/app?sslmode=disable'
Enter fullscreen mode Exit fullscreen mode

Open http://127.0.0.1:8080. Done. No installer, no runtime,
no 47-step setup wiki.

Already have DATABASE_URL exported? Just run dbadminer.
It also understands PG* vars, MYSQL_*, DB_*, and
Docker-style POSTGRES_*. It'll find your database the way a
dog finds a dropped sandwich.

"Read-only" actually means read-only

Not "we hid the delete button" read-only. Properly:

  • Only one SELECT, WITH, EXPLAIN, VALUES, TABLE, or SHOW per request
  • INSERT, UPDATE, DELETE, CREATE, ALTER, DROP are rejected before they reach your database
  • Postgres, MySQL, and MariaDB also run queries in a read-only transaction, a second lock on the door
  • SQLite opens with mode=ro
  • The write UIs stay hidden, and the write APIs return 403

Belt, suspenders, and a rope.

When you really need to change things:

dbadminer --access=full
Enter fullscreen mode Exit fullscreen mode

Now you get create/alter/drop dialogs, index and foreign-key
actions, and row editing in the grid. Use it wisely. Or at
least not on a Friday.

Don't want another app? Embed it.

This is my favorite part. If you already have a *sql.DB,
DBAdminer lives right next to it:

cfg := dbadminer.DefaultConfig()
ex, err := dbadminer.New(db, cfg)
if err != nil {
    log.Fatal(err)
}
if err := ex.ListenAndServe(ctx); err != nil {
    log.Fatal(err)
}
Enter fullscreen mode Exit fullscreen mode

The library imports only the standard library. The CLI is a
separate module, so importing DBAdminer won't drag a pile of
database drivers into your go.mod. Your dependency graph
stays calm.

You can also mount ex.Handler() on your own server. There are
examples for net/http, chi, and cobra.

Docker, because of course

docker run --rm -p 127.0.0.1:8080:8080 \
  -e DATABASE_URL='postgres://postgres:5432/app?sslmode=disable' \
  dbadminer
Enter fullscreen mode Exit fullscreen mode

Need several databases at once? Set DBADMINER_DATABASES=shop,app
and give each name its own prefixed variables
(SHOP_DATABASE_URL, APP_DB_USER, and so on). The README has
a full Compose example.

Paranoid by design

A tool that connects to your database should be a little
suspicious of everyone, so:

  • Binds to loopback (127.0.0.1) by default
  • Rejects requests with a non-loopback Host header
  • Checks that Origin matches
  • Optional basic auth for the page (--user / --password)
  • Limits for rows, query timeout, request body, and response size

Why I built it

It started with a simple wish: I just want to look at my database.

That's it. No grand plan. I was working on a project, I needed
to see some tables, and I wanted something Adminer-like. Easy,
right?

Reader, it was not easy.

  • Paid tools: great, but I wasn't looking to open my wallet to view a table.
  • DBeaver: it kept trying to download drivers, and where I work (behind a firewall), it kept asking me about it with pop-ups. Pop-up. Pop-up. Pop-up. I started to feel like the tool was trying to tell me something.
  • Beekeeper Studio: a trial, and one more closed-source desktop app to install and run.

What I really wanted was boring and simple: a tiny image I
can drop into my existing docker-compose.yml
and forget about.
docker compose up, open a browser tab, done. No installers.
No driver downloads. No "please sign in to continue".

So I built exactly that. DBAdminer is one small Go binary (or
image) that sits next to your database like a polite houseguest.

Safety is the server's job, not the login form's

Most admin tools work like this: type the right username and
password, and you get the keys to everything.

DBAdminer works differently. The server decides what's
allowed, not whoever logged in.

  • It starts read-only. The mode is set in your config (--access or DBADMINER_ACCESS), not by what the browser asks for.
  • Write statements are rejected server-side before they reach your database, and the write APIs return 403.
  • Basic auth (--user / --password) only protects the page. It never turns on write access.

So even if someone gets into the page, they can look but not
touch. Want to allow writes? That's a deliberate decision, made
in your config and not by a button in the UI.

Try it, break it, tell me about it

⭐ Repo: https://github.com/dbadminer/dbadminer

Found a bug? Want MSSQL, dark mode, or a feature I haven't
thought of? Open an issue or send a PR. And if you try it, tell
me in the comments what database you pointed it at.

(If it's production, I hope you stayed read-only.)

Top comments (0)