Documentation

Architecture

QueryGlow is built so your data stays on your server. It runs as a self-contained Node.js process inside Docker. Its only calls to third-party services are the optional Ask AI requests to the provider you chose; the browser loads the Monaco editor from cdn.jsdelivr.net. The app never checks for updates: ./queryglow update runs git fetch against your own remote, only when you run it.

The Tech Stack

  • Next.jsHandles the React frontend (Monaco Editor, Data Grid) and the API backend in one Node.js 22 process. The container starts next directly and runs as a non-root user.
  • DriversDirect native connections using pg (PostgreSQL, CockroachDB, TimescaleDB), mysql2 (MySQL, MariaDB), and better-sqlite3 (SQLite).knex is used only for MySQL, MariaDB and SQLite.
  • Ask AIStateless requests to OpenAI, Anthropic or Google with your own key. Ask AI sends your database type, table and column names with their types, and your prompt. Never rows. Keys come from .env or are entered in the app and stored encrypted in ai-settings.json; a key in .env wins. Rate limited to 30 requests per minute at nginx (standalone mode).
  • Host toolingThe queryglow shell command runs on the host for install, update, status, backup and doctor. It needs bash, git, Docker with the compose plugin and curl; no Node.js on the host.
  • TimeThe server process runs in UTC, so timestamps reach the browser as stored. The browser formats them with the time zone and format set in Preferences.

Request Lifecycle

  1. Authentication (nginx Layer)

    Request hits nginx first. Basic Auth checks the credentials against the htpasswd file, and nginx applies a general rate limit (standalone mode). If valid, nginx proxies to 127.0.0.1:3000 (or the port the installer picked).

  2. CSRF Validation (API Layer)

    For state-changing requests (POST, PUT, PATCH, DELETE), the API refuses a request marked cross-site by the browser or whose Origin header does not match the Host. Cross-origin requests are blocked.

  3. Decryption

    The API route reads connections.json and decrypts the stored password with AES-256-GCM authenticated encryption, using a key derived from SESSION_SECRET and ENCRYPTION_SALT. Tampered ciphertext fails to decrypt.

  4. Safe Mode Check (Query Editor and Agents)

    If Safe Mode is enabled (default), destructive queries are blocked: DROP TABLE, TRUNCATE, DELETE/UPDATE without WHERE clause. Data Browser buttons do not go through this check. On a connection marked production, the Query Editor also asks for confirmation before any write.

  5. Tunneling (Optional)

    If SSH Tunneling is enabled, the app opens a local listener on 127.0.0.1 with a random port, connects to your bastion over SSH and forwards the database traffic through it. The bastion's host key is pinned on first use; a changed key is refused with both fingerprints.

  6. Execution

    The driver connects (either directly or via the local tunnel port) and executes the SQL. SSL connections can verify the server certificate (Verify server certificate option). Results come back to the UI as JSON.

Agent Access Path

AI agents call /api/mcp, which skips Basic Auth and requires a Bearer token instead (tokens are stored only as SHA-256 hashes). The app rate limits the endpoint per IP and overall, runs the same query guard, then executes one statement per call inside a read-only transaction enforced by the database (for read-only tokens), with a per-statement timeout. Every call, including refused and paused ones, is recorded in the Activity tab. Agent Access guide

Security Layers

QueryGlow uses defense in depth with multiple independent security layers:

Internet → HTTPS/SSL → nginx → Basic Auth → QueryGlow on localhost (CSRF check, Safe Mode) → SSH Tunnel → Remote DB
  • Network Isolation: QueryGlow binds to 127.0.0.1:3000 only. Not accessible from external network.
  • Credential Encryption: AES-256-GCM with scrypt key derivation. Unique salt per installation (written by the installer).
  • SQL Injection Prevention: Identifier escaping + parameterized queries for all user input.
  • SQLite Sandboxing: File paths restricted to the /app/data directory only.
  • CSV Export Protection: Formula injection characters are sanitized to prevent Excel/Sheets exploits.

File-System Persistence

QueryGlow does not use an external database for its own state. It keeps JSON files in the Docker volume, written atomically and one writer at a time. ./queryglow backup copies them, together with .env, to backups/<timestamp>/.

/app/data/connections.json

Connection profiles. Passwords, SSH private keys and SSH passphrases are AES-256-GCM encrypted.

/app/data/query-history.json

Rolling log of the last 1,000 executed queries across all connections.

/app/data/saved-queries.json

Saved SQL snippets with names for quick reuse.

/app/data/agent-tokens.json, agent-activity.json

Agent tokens (SHA-256 hashes only) and the log of agent calls shown in the Activity tab.

/app/data/ai-settings.json

AI provider keys (encrypted) and models entered in the app.

/app/data/ssh-known-hosts.json

SSH host key fingerprints pinned on first connect.

Important: SESSION_SECRET and ENCRYPTION_SALT in your .env file derive the encryption key. Without them, you cannot decrypt saved connection passwords, SSH keys or AI keys. Back up the data and .env together.