#What it is
Grove is a polyglot Go ORM that generates each database's native query syntax rather than a portable subset. The common core handles connections, cached metadata, migrations, hooks and streaming; each driver exposes a builder that speaks its own dialect.
#Supported databases
- PostgreSQL: $1 placeholders, DISTINCT ON, FOR UPDATE, JSONB operators. Also CockroachDB, Neon and Supabase.
- MySQL: backtick quoting, ON DUPLICATE KEY UPDATE, USE INDEX hints. Also TiDB.
- SQLite: INSERT OR REPLACE.
- MongoDB: native BSON filter documents and aggregation pipelines. Also FerretDB.
- Turso / libSQL: embedded replicas and multi-region replication.
- ClickHouse: MergeTree engines, PREWHERE, SAMPLE, batch inserts.
#Performance
On the insert benchmark (SQLite in-memory, go1.25.7, darwin/arm64, five runs averaged):
- Raw database/sql: 4,015 ns/op, 880 B/op, 20 allocations
- Grove: 4,381 ns/op, 1,283 B/op, 28 allocations, about 9 per cent over raw
- Bun: 8,459 ns/op, 5,470 B/op, 27 allocations, about 111 per cent over raw
- GORM: 10,265 ns/op, 4,954 B/op, 66 allocations, about 156 per cent over raw
The mechanism is that struct metadata is resolved once at registration and cached, so the query path walks a prepared description rather than the reflect API, with pooled buffers. Against a network round trip to a real database these differences are noise; they matter on bulk paths and inside Fabriq, where per-command overhead is multiplied by a fan-out.
#Other pieces
- Dual tags: bun:"..." is read as a fallback when grove:"..." is absent, so a Bun codebase can adopt Grove without touching its models.
- Modular migrations: written in Go, with dependency ordering across modules, which is what a plugin-shaped application needs.
- Privacy hooks: pre and post query hooks for tenant isolation, PII redaction and audit logging.
- Streaming: server-side cursors with per-row hooks.