Terminal-based PostgreSQL Editor

Your database,
in your terminal.

floz-editor is a production-grade TUI for PostgreSQL. Browse schemas, CRUD rows, filter data, navigate foreign keys, and manage connections — all without leaving your terminal.

📊

Data Grid

Horizontal scroll, column resize, reorder. Deterministic pagination with 100-row chunks.

🌳

Schema Explorer

Collapsible schema tree with lazy-loaded tables. Navigate with vim keys or arrows.

🔍

Dual Filtering

Global fuzzy search (/) and structured filter builder (F) with 7 operators per column.

✏️

Full CRUD

Create, edit, and delete rows with primary-key-bound mutations. Read-only mode for safety.

🔗

FK Navigation

Expand parent rows to child data. Jump into related tables with breadcrumb tracking.

💾

Session Persistence

Remembers last schema, table, column widths, and ordering across restarts.

Installation

# From source (requires Rust toolchain)
git clone https://github.com/hanuman-org/floz-editor.git
cd floz-editor
cargo install --path .

# Or build directly
cargo build --release
./target/release/floz-editor --url postgres://localhost/mydb

Quick Start

# Minimal — connects using DATABASE_URL env var
floz-editor

# Specify connection URL
floz-editor --url postgres://user:pass@localhost:5432/mydb

# Read-only mode (safe for production)
floz-editor --url postgres://prod-host/db --read-only

# Start in a specific schema
floz-editor --schema accounting

# Custom config file
floz-editor --config ./my-editor.toml

# Color theme
floz-editor --theme dracula

Data Grid

The primary view. Displays table data in a scrollable grid with column metadata, pagination, and dynamic OID-based type decoding.

Navigation

j / move cursor down  k / move up  scroll columns horizontally

Column Operations

Alt+← / Alt+→ resize column width  Ctrl+← / Ctrl+→ reorder columns (swap)

Pagination

Rows load in 100-row chunks. As you scroll near the bottom, floz-editor automatically pre-fetches the next chunk — seamless infinite scrolling with deterministic offset-based pagination.

Dynamic Type Decoding

Columns are decoded dynamically from PostgreSQL OIDs at runtime — no compile-time schema needed. Supports all standard types: int4, text, bool, timestamptz, uuid, jsonb, numeric, arrays, and more. Long values are truncated to keep the grid readable.

Schema Explorer

Press h or from the data grid to open the left-pane schema tree.

Schemas are discovered from information_schema.schemata (excluding internal PG schemas). Tables are lazy-loaded when a schema node is expanded. Tables are marked with PK status for mutability awareness.

Controls

j / k navigate  Enter expand schema or select table  l / / Esc return to grid

System schemas (pg_catalog, information_schema, pg_toast) are automatically hidden. Additional schemas can be hidden via hidden_schemas in the config file.

Filtering

Fuzzy Search /

Press / to enter filter mode. Type a search term — it's applied as a global ILIKE '%term%' across all text-castable columns. Press Enter to apply, Esc to cancel.

Advanced Filter Builder F

Press F to open the structured filter modal. Build complex queries with per-column conditions:

OperatorSQLDescription
Exact=Exact match
ContainsILIKE '%..%'Case-insensitive substring
Not Equal!=Not equal
Greater Than>Greater than
Less Than<Less than
Is NullIS NULLNull check
Is Not NullIS NOT NULLNon-null check

Multiple conditions are joined with AND / OR gates (toggleable). Navigate with j/k for rows and h/l for columns.

CRUD Operations

All write operations are PK-bound for safety. Tables without primary keys are automatically detected as read-only.

Create Row n

Opens a form with all columns. Tab/Shift+Tab to navigate fields. Ctrl+N to toggle NULL. Enter to submit, Esc to cancel.

Edit Row Enter

Opens an edit form pre-filled with the current row values. Only modified fields are included in the UPDATE.

Delete Row d

Shows a confirmation prompt. Press y to confirm, any other key to cancel. DELETE is bound to the row's primary key.

Read-only mode: Launch with --read-only to disable n, d, and Enter mutation keys entirely. PK-less tables are automatically read-only.

Child Expansion & FK Navigation

Foreign keys are auto-discovered from pg_constraint. Supports single and composite FK relationships.

Expand Child Pane Tab

Press Tab to open the child split-pane showing related records for the selected row. Press Tab again to cycle through FK relations if a table has multiple.

Jump Into Child Table l

With the child pane open, press l to navigate into the child table. The current position is pushed onto a breadcrumb stack.

Go Back Esc / b

Pop the breadcrumb stack and return to the parent table with the previous filter and cursor position.

Child rows are cached using a DashMap-based concurrent cache, with manual invalidation on r (refresh).

Keybindings

KeyModeAction
q / Ctrl+cGlobalQuit
?NormalToggle help modal
j / NormalMove cursor down
k / NormalMove cursor up
/ NormalScroll columns
hNormalOpen schema explorer
Alt+← / Alt+→NormalResize column
Ctrl+← / Ctrl+→NormalReorder columns
/NormalFuzzy filter mode
FNormalAdvanced filter builder
nNormalNew row form
EnterNormalEdit row form
dNormalDelete row (confirm)
r / F5NormalRefresh data + clear cache
TabNormalToggle/cycle child FK pane
lNormalJump into child table
b / EscNormalGo back (breadcrumb pop)
eNormalDismiss error bar
SNormalServer stats panel
CNormalActive connections panel
Ctrl+NFormToggle NULL on field
TabFormNext field
Shift+TabFormPrevious field

Configuration

Configuration via floz-editor.toml in the current directory (or --config path).

# floz-editor.toml

[database]
url = "postgres://user:pass@localhost:5432/mydb"

[editor]
read_only = false
default_schema = "public"
hidden_schemas = ["pg_catalog", "information_schema"]
nerd_font = true

Priority Resolution

Database URL: --url CLI → [database] url TOML → DATABASE_URL env var.
Schema: --schema CLI → default_schema TOML → "public".
Read-only: --read-only CLI ∨ read_only TOML.

Session Persistence

floz-editor saves your session to ~/.config/floz-editor/session.toml containing:

  • last_schema / last_table — resume where you left off
  • expanded_schemas — which tree nodes were open
  • custom_col_widths — per-column width overrides
  • custom_col_order — per-table column reordering

Disable with --no-session.

Server Stats & Connections

Server Stats S

View PostgreSQL version, uptime, database size, active backends, cache hit ratio, and system resources.

Active Connections C

View all active database connections from pg_stat_activity. Navigate with j/k and kill connections with k. The editor sets application_name = 'floz-editor' for easy identification.

Architecture

floz-editor/src/
├── main.rs            ← CLI parsing, pool setup, entry point
├── config.rs          ← Cli + Config + Session structs
├── channel.rs         ← Tokio MPSC Action enum
├── app/
│   ├── mod.rs         ← Main event loop (render + dispatch)
│   ├── state.rs       ← AppState (all TUI state)
│   ├── events.rs      ← Action → side-effect handlers
│   └── input.rs       ← Keyboard input → Action dispatch
├── db/
│   ├── introspect.rs  ← Schema/table/PK/FK discovery
│   ├── decode.rs      ← Dynamic OID-based row decoding
│   └── worker.rs      ← Background DB queries (non-blocking)
├── ui/                ← Ratatui widgets
│   ├── grid.rs, explorer.rs, form.rs, footer.rs
│   ├── confirm.rs, help.rs, stats.rs, connections.rs
│   ├── child.rs, advanced_search.rs
├── mutation.rs        ← Form state + mutation payload builder
├── cache.rs           ← DashMap child-data cache
├── types.rs           ← Shared types (Row, ColumnMeta, etc.)
├── telemetry.rs       ← Server stats + pg_stat_activity
└── logger.rs          ← 30-day rotating tracing logs

Non-Blocking Architecture

All database operations run on a separate Tokio task via an MPSC channel (Action enum). The TUI render loop never blocks. Results are sent back through the same channel and applied to AppState on the main thread.

Dependencies

ratatui 0.29 crossterm 0.28 sqlx 0.8 tokio dashmap 6 clap 4 serde toml 0.8 tracing sysinfo anyhow

Logging

floz-editor writes structured logs using tracing + tracing-appender with 30-day automatic rotation. Logs are written to ~/.config/floz-editor/logs/.

Log level is controlled via the RUST_LOG environment variable: RUST_LOG=debug floz-editor.