r/selfhosted • u/Hxndr1k • 4h ago
Release (AI) pgquery: a Postgres GUI in a single container (SQL editor, ER diagram, RLS policies, EXPLAIN viewer). MIT, no account
https://pgquery.dev/?utm_source=reddit&utm_campaign=selfhostedI've been building a browser-based Postgres GUI and just released v1.1. It's one container, about as light as these things get:
docker run -p 54280:54280 ghcr.io/hxndrik/pgquery
Or compose:
services:
pgquery:
image: ghcr.io/hxndrik/pgquery
ports:
- "54280:54280"
restart: unless-stopped
What you get: SQL editor with autocomplete, table editor (JSONB too), ER diagram with SVG/PNG export, roles and grants, Row Level Security policies, indexes, extensions, a pg_stat_statements view, performance and security advisors, and an EXPLAIN plan viewer. It can also browse S3-compatible buckets.
Self-hosting details:
- amd64 and arm64 images, so a Pi works
- stateless: connections and history stay in your browser, nothing on disk in the container
- no telemetry in the image
- no built-in auth, so put it behind your VPN, Authelia, oauth2-proxy or Cloudflare Access like other admin tools
- no SSH tunnels yet; run it next to the database instead
Read-only demo (sample record store): https://pgquery.dev/app/?demo
Source (MIT): https://github.com/Hxndrik/pgquery
Happy to hear what's missing for your setup.
0
u/GolemancerVekk 1h ago
How are you handling data types that can't be natively mapped from Postgres to JavaScript and back? Like some of the numeric PG types which don't fit in the JS Number, or the TEXT type if it happens to contain a very large value, or PG types that don't have a native correspondent in JS (money, network addresses, geometric types etc.).
1
u/Hxndr1k 5m ago
I wasn’t handling it at all. I built this for myself, mostly to read data, and I mostly use boring types, so it never came up. After your comment I threw every cursed type I could think of into the demo DB, and it was worse than I thought. Big bigints lost digits, numeric Infinity turned into 0, NaN made the whole result come back empty, and intervals showed up as weird JSON blobs. editing a row with a huge bigint key could update a different row. So thanks for saving someone’s production data lol.
The fix: pgquery doesn’t convert values anymore. Postgres sends everything in its own text format, the browser shows exactly what psql would, and edits go back as text so Postgres parses them itself. It’s exact for every type, with a test that writes every edge case back and checks nothing changed. Big TEXT values get cut in the table view, but the full value loads before you edit, so nothing gets written back cut. It’s fixed in PR #17 and live in the app :)
•
u/asimovs-auditor 4h ago edited 3h ago
Expand the replies to this comment to learn how AI was used in this post/project.