Introduction
FluxaORM is a code-generation-first ORM for Go, purpose-built for MySQL and Redis, with query-only ClickHouse support for analytics and Apache Kafka integration for event streaming. Instead of relying on runtime reflection to map structs to database rows, FluxaORM generates fully typed Go code from your entity definitions — giving you compile-time safety, zero-reflection data access, and built-in dirty tracking.
How It Works
The FluxaORM workflow has four steps:
- Define entity structs with
orm:struct tags - Register entities and connection pools in a
Registry - Validate the registry to produce an
Engine, then callGenerate()to emit typed Go code - Use the generated
ProviderandEntitytypes in your application
package main
import (
"context"
"fmt"
"github.com/latolukasz/fluxaorm/v2"
)
// Step 1: Define your entity struct
type UserEntity struct {
ID uint64 `orm:"redisCache"`
Name string `orm:"required"`
Email string `orm:"required"`
Age uint8
}
func (e UserEntity) UniqueIndexes() map[string][]string {
return map[string][]string{"Email": {"Email"}}
}
func main() {
// Step 2: Register entities and pools
registry := fluxaorm.NewRegistry()
registry.RegisterMySQL("root:root@tcp(localhost:3306)/app", fluxaorm.DefaultPoolCode, nil)
registry.RegisterRedis("localhost:6379", 0, fluxaorm.DefaultPoolCode, nil)
registry.RegisterLocalCache(fluxaorm.DefaultPoolCode, 100000)
registry.RegisterEntity(&UserEntity{})
// Step 3: Validate and generate
engine, err := registry.Validate()
if err != nil {
panic(err)
}
err = fluxaorm.Generate(engine, "./entities")
if err != nil {
panic(err)
}
}
After running this program, the ./entities directory will contain generated code including a UserEntityProvider and a UserEntity type with typed getters and setters.
Using Generated Code
package main
import (
"context"
"fmt"
"github.com/latolukasz/fluxaorm/v2"
"myapp/entities"
)
func main() {
// ... registry setup and validation as above ...
ctx := engine.NewContext(context.Background())
// Create a new entity
user := entities.UserEntityProvider.New(ctx)
user.SetName("Alice")
user.SetEmail("alice@example.com")
user.SetAge(30)
err := ctx.Flush()
if err != nil {
panic(err)
}
// Fetch by ID
user, found, err := entities.UserEntityProvider.GetByID(ctx, 1)
if err != nil {
panic(err)
}
if found {
fmt.Println(user.GetName()) // "Alice"
fmt.Println(user.GetAge()) // 30
}
// Search with type-safe query builder
users, err := entities.UserEntityProvider.SearchMany(ctx,
fluxaorm.NewQuery().
Filter(entities.UserEntityProvider.Fields.Age.Gte(18)).
SortByASC(entities.UserEntityProvider.Fields.Name),
)
if err != nil {
panic(err)
}
for _, u := range users {
fmt.Println(u.GetName(), u.GetEmail())
}
}
Designed for MySQL
Unlike generic ORM libraries that abstract away database differences behind a lowest-common-denominator interface, FluxaORM is specifically tailored for MySQL. This allows it to take full advantage of MySQL-specific features, optimizations, and DDL semantics — including automatic schema migrations, proper ENUM/SET types, and efficient connection pool management based on your server's max_connections and wait_timeout settings.
Three-Tier Caching
FluxaORM provides a transparent, three-tier caching system for entity reads:
- Context cache — a per-request in-memory cache with a configurable TTL (default: 1 second). Populated automatically by
GetByIDandGetByIDs. Zero configuration required. - Local cache — a per-process LRU cache stored in application memory. Configured per pool with a maximum key count.
- Redis cache — entities are serialized into Redis Lists, enabling fast lookups that bypass MySQL entirely. Enabled per entity with the
orm:"redisCache"struct tag.
When an entity is requested, FluxaORM checks each tier in order and only falls through to MySQL when no cached copy is available. Cache invalidation is handled automatically when entities are modified and flushed.
Redis Search
Entities can opt in to Redis Search indexing via struct tags. The ORM automatically maintains Redis hash documents and FT.SEARCH indexes, enabling full-text and numeric queries that run entirely in Redis.
Dirty Tracking and Flush
Generated entity setters compare new values against the original database values and only mark changed fields as dirty. When you call ctx.Flush(), FluxaORM batches all pending INSERT, UPDATE, and DELETE operations into efficient SQL statements and updates Redis caches in a single pass.
For non-critical writes, ctx.FlushAsync(true) publishes SQL operations to a Kafka topic for asynchronous processing while updating cache immediately, and ctx.FlushAsync(false) defers both SQL and cache updates to the consumer.
Built-in Redis Client
FluxaORM includes its own Redis client with support for all standard commands plus additional features like distributed locks and rate limiters. No external Redis client library is needed.
Requirements
FluxaORM requires Redis 8.2 or later. The Validate() method will return an error if any registered Redis pool is running an older version.
ClickHouse Support
FluxaORM provides query-only ClickHouse integration for analytics, reporting, and direct SQL operations. Register a ClickHouse pool alongside your MySQL and Redis pools, then use engine.Clickhouse(code) to execute raw queries — no entity mapping or schema management involved. See ClickHouse Queries for details.
Kafka Support
FluxaORM integrates with Apache Kafka via the franz-go library, providing sync/async producing, consumer group support, and SASL authentication. Register a Kafka pool, then use engine.Kafka(code) to produce and consume messages with built-in logging and metrics. See Kafka for details.
What's Next
Continue to the Registry page to learn how to configure connection pools and register entities, or jump to Data Pools for details on MySQL, Redis, ClickHouse, Kafka, and local cache pool options.