Glimt is a lightweight SQL toolkit for Go that keeps queries in .sql files
while allowing safe runtime composition of predicates.
Many applications prefer writing SQL in .sql files instead of embedding
large queries directly in code. However, APIs still need to dynamically add:
- filters
- search conditions
- pagination
Glimt keeps your core SQL declarative, while allowing flexible runtime query composition:
-- :name listUsers
SELECT * FROM usersimport gl "github.com/mochams/glimt"
reg := gl.NewRegistry(gl.DialectPostgres)
users := reg.MustGet("listUsers").Where(gl.Eq("status", "active"))
users.Where(gl.Eq("role", "admin"))
users.Limit(10)
users.Offset(2)
sql, args := users.Build()Generated SQL (Postgres):
SELECT * FROM users
WHERE status = $1 AND role = $2
LIMIT $3 OFFSET $4Generated Args:
["active", "admin", 10, 2]Glimt lets you write SQL once and compose predicates dynamically.
Installation
go get github.com/mochams/glimtDefine queries in .sql files and load them by name.
-- :name listUsers
SELECT * FROM usersreg := gl.NewRegistry(gl.DialectPostgres)
reg.LoadFile("queries/users.sql")
admins, args := reg.MustGet("listUsers").
Where(gl.Eq("role", "admin")).
Limit(10).
Build()
user, args := reg.MustGet("listUsers").
Where(gl.Eq("id", "user_id")).
Limit(1).
Build()Work seamlessly with Go's embed.
//go:embed queries
var sqlFiles embed.FS
reg := gl.NewRegistry(gl.DialectPostgres)
reg.LoadFS(sqlFiles, "queries")Glimt lets you build queries directly in Go when needed
reg := gl.NewRegistry(gl.DialectPostgres)
sql, args := reg.Query("SELECT * FROM users").
Where(gl.And(
gl.Eq("status", "active"),
gl.Gt("age", 18),
)).
OrderBy("created_at DESC").
Limit(20).
Offset(0).
Build()Queries are defined using -- :name annotations.
-- :name listUsers
SELECT * FROM users
-- :name deleteUser
DELETE FROM users WHERE id = ?Query names must be unique across all loaded files.
For dynamic filtering, avoid writing a top-level WHERE clause in the base query.
Instead attach conditions through the builder:
-- :name listUsers
SELECT * FROM usersadmins := reg.MustGet("listUsers").
Where(gl.Eq("role", "admin")).
Build()
guests := reg.MustGet("listUsers").
Where(gl.Eq("role", "guest")).
Build()One base query, multiple use cases, no duplication.
Glimt automatically writes placeholders for the target database.
| Database | Placeholders |
|---|---|
| Postgres | $1, $2, $3 |
| MySQL, SQLite | ?, ?, ? |
| SQL Server | @p1, @p2, @p3 |
| Oracle | :1, :2, :3 |
SQL files should always use ? placeholders. They are rewritten to the correct format at build time.
Glimt aims to stay SQL-first, Composable, Lightweight, and Dependency-free
See the full example in example.
Full API documentation is available at:
https://pkg.go.dev/github.com/mochams/glimt
Inspiration
Glimt is inspired by Yesql, a Clojure library by Kris Jenkins that encourages writing SQL in SQL rather than embedding it in application code.
Glimt extends this idea with composable predicates, making it easier to build dynamic queries for APIs and search endpoints.