Installation
Quark is a regular Go module built on top of database/sql. You install the ORM
once, then add the driver package for the database engine your application uses.
Requirements
| Requirement | Notes |
|---|---|
| Go 1.25+ | Quark declares go 1.25.7 in go.mod; build with Go 1.25 or newer. Uses generics and the modern module-aware toolchain. |
A database/sql driver | The driver owns the wire protocol and DSN format. Imported with the blank-import idiom. |
Driver name passed to quark.New | Quark auto-detects the dialect from the driver name; override with WithDialect when registering a custom dialect. |
go get github.com/jcsvwinston/quark
import "github.com/jcsvwinston/quark"
Quark is at v1.1.0 on the stable v1.x line. The query builder, CRUD methods,
transactions, batch operations, schema helpers, cache abstraction, and tenant
router are part of the public package. A standalone cmd/quark binary ships in the
module tree — install it with go install github.com/jcsvwinston/quark/cmd/quark@latest
for migrations, model generation, schema inspection, and tenant operations (see
Operational Workflows). The Go APIs in Migrations and Sync stay
available for in-process workflows.
Driver Packages
Install exactly the driver you need. Quark does not wrap or replace driver DSNs.
| Engine | Suggested driver | Dialect option |
|---|---|---|
| SQLite | modernc.org/sqlite | quark.SQLite() |
| PostgreSQL | github.com/lib/pq | quark.PostgreSQL() |
| MySQL | github.com/go-sql-driver/mysql | quark.MySQL() |
| MariaDB | github.com/go-sql-driver/mysql | quark.MariaDB() |
| SQL Server | github.com/microsoft/go-mssqldb | quark.MSSQL() |
| Oracle | github.com/sijms/go-ora/v2 | quark.Oracle() |
go get modernc.org/sqlite
go get github.com/lib/pq
go get github.com/go-sql-driver/mysql
go get github.com/microsoft/go-mssqldb
go get github.com/sijms/go-ora/v2
SQLite is the simplest local starting point because it needs no external service.
For MySQL and MariaDB, include parseTime=true in the DSN when you scan
time.Time fields.
MariaDB has no dedicated database/sql driver — it speaks the MySQL wire
protocol through github.com/go-sql-driver/mysql (driver name "mysql").
Quark detects MariaDB automatically: on a "mysql" connection it probes
SELECT VERSION() once at New() and switches to the MariaDB dialect when the
server identifies as MariaDB. So quark.New("mysql", dsn) picks the right
dialect for both engines. Passing WithDialect(quark.MariaDB()) explicitly
still works and skips the probe.
Optional Packages
| Package | Purpose |
|---|---|
github.com/jcsvwinston/quark/cache/memory | In-process CacheStore with tag invalidation. |
github.com/jcsvwinston/quark/cache/redis | Redis-backed CacheStore. |
github.com/jcsvwinston/quark/otel | OpenTelemetry middleware. |
github.com/jcsvwinston/quark/migrate | Versioned migration registry and migrator. |
The core package has no framework dependency. You can use it from HTTP handlers,
workers, CLIs, tests, or any service layer that can pass a context.Context.
Minimal Client
package main
import (
"context"
"log"
"github.com/jcsvwinston/quark"
_ "modernc.org/sqlite"
)
type User struct {
ID int64 `db:"id" pk:"true"`
Email string `db:"email" quark:"unique,not_null"`
Name string `db:"name" quark:"not_null"`
}
func main() {
client, err := quark.New("sqlite", "file:quark.db?cache=shared")
if err != nil {
log.Fatal(err)
}
defer client.Close()
ctx := context.Background()
if err := client.Migrate(ctx, &User{}); err != nil {
log.Fatal(err)
}
user := User{Email: "alice@example.com", Name: "Alice"}
if err := quark.For[User](ctx, client).Create(&user); err != nil {
log.Fatal(err)
}
log.Printf("created user id=%d", user.ID)
}
quark.New pings the database during construction. Treat a returned error as a
startup failure: wrong DSN, unreachable database, credentials rejected, or a
driver/dialect mismatch.
Switching Engines
The model and query code do not change when you change the database. The driver
import and the driver name passed to quark.New do.
import (
"github.com/jcsvwinston/quark"
_ "github.com/lib/pq"
)
client, err := quark.New("postgres", "postgres://user:pass@localhost/app?sslmode=disable")
if err != nil {
return err
}
The dialect is auto-detected from the driver name. It controls placeholder
syntax, identifier quoting, RETURNING behavior, upsert fragments, JSON
expressions, pagination, and DDL.
Pool Configuration
Quark owns the *sql.DB it creates. Configure the pool through the
WithMaxOpenConns, WithMaxIdleConns, and WithConnMaxLifetime options:
client, err := quark.New("postgres", dsn,
quark.WithMaxOpenConns(25),
quark.WithMaxIdleConns(25),
quark.WithConnMaxLifetime(30*time.Minute),
)
For database-per-tenant routing, each tenant can own its own *sql.DB pool. See
Multi-Tenant before setting high pool limits.
Smoke Test
Use this to verify that the driver, dialect, migration helper, insert path, and primary-key writeback all work:
func Smoke(ctx context.Context, client *quark.Client) error {
type HealthCheck struct {
ID int64 `db:"id" pk:"true"`
Name string `db:"name" quark:"not_null"`
}
if err := client.Migrate(ctx, &HealthCheck{}); err != nil {
return err
}
row := HealthCheck{Name: "ok"}
if err := quark.For[HealthCheck](ctx, client).Create(&row); err != nil {
return err
}
_, err := quark.For[HealthCheck](ctx, client).Find(row.ID)
return err
}
Integration Test DSNs
The upstream test suite uses environment variables for external engines. SQLite tests can run offline.
export QUARK_TEST_POSTGRES_DSN="postgres://user:pass@localhost:5432/testdb?sslmode=disable"
export QUARK_TEST_MYSQL_DSN="user:pass@tcp(localhost:3306)/testdb?parseTime=true"
export QUARK_TEST_MSSQL_DSN="sqlserver://sa:Pass@localhost:1433?database=testdb"
export QUARK_TEST_ORACLE_DSN="oracle://user:pass@localhost:1521/XE"
When a test or local tool uses raw DDL through client.Exec, configure the client
with AllowRawQueries: true. The high-level Migrate, Sync, CreateIndex,
and AddForeignKey helpers do not require raw-query opt-in.