A database model code generator for Go. Generate ORM models from database schema using bun framework.
- Supports MySQL and PostgreSQL databases
- Automatic Go type mapping for database columns
- Automatic foreign key detection and relation generation (belongs-to, has-many)
- Composite unique index detection (
unique,unique:index_nametags) - Customizable templates
- Custom struct generation — define non-DB structs for JSON columns, value objects, configuration objects
- Custom field names, types, comments, tags, and multi-line comments
- Naming conventions (snake_case, camelCase, consecutive acronyms)
- Timezone support for created_at, updated_at, deleted_at hooks
- Environment-based configuration (e.g., bake.gen.dev.yaml for env=dev)
- Concurrent table processing
- Auto-detect database driver from DSN scheme
| Category | Expressions | Description |
|---|---|---|
| Comparison | Eq, Neq, Gt, Gte, Lt, Lte |
Basic comparisons |
| String | Like, LikePrefix, LikeSuffix, LikeContain |
Pattern matching |
| Numeric | In, NotIn, Between, NotBetween |
Range operations |
| Aggregate | SUM, AVG, MIN, MAX |
Aggregate functions |
| Arithmetic | Add, Sub, AddLeast, SubGreatest, Clamp |
Arithmetic operations |
| Time | Date, Year, Month, Day, Hour, Minute, Second |
Time extraction |
| Nullable | IsNull, IsNotNull, Coalesce |
NULL handling |
| Ordering | Asc, Desc |
Sort order |
go install github.com/sishui/bake/cmd/bake@latest- Initialize a configuration file:
bake init-
Edit
bake.gen.yamlwith your database connection details -
Generate models:
bake| Command | Description |
|---|---|
bake init |
Initialize a configuration file in current directory |
bake version |
Show current version |
bake |
Generate models based on configuration |
log:
level: "info" # debug, info, warn, error
file: "" # log file path (optional)
uncountables: ["sms", "mms", "rls"] # words that should not be pluralized
initialisms: ["ID", "URL", "URI", "UUID", "IP"] # naming conventions
timezone: "Asia/Shanghai" # timezone for time hooks
template:
dir: "" # custom template directory
model: "model" # template filename
output:
dir: "model" # output directory
package: "model" # package name
module: "github.com/username/project" # module path for imports
db:
- driver: "postgres"
dsn: "postgres://user:pass@localhost:5432/db?sslmode=disable"
schema: "public" # required for postgres, optional for mysql
included: [] # tables to include (default: all)
excluded: [] # tables to exclude (default: none)When .env contains env=dev, bake looks for bake.gen.dev.yaml first, then falls back to bake.gen.yaml.
db:
- driver: "postgres"
# ...
customs:
users:
comment: "User table" # custom table comment
tags:
- key: "form"
name: "$SnakeCase" # convert to snake_case
- key: "xml"
name: "$CamelCase" # convert to camelCase
fields:
created_at: # database column name
name: "CreatedAt" # custom field name
tags:
- key: "json"
name: "created_at" # custom json tag name
posts:
fields:
author_id:
name: "Author" # custom field name
type: "*User" # custom field type
relation: true # is a relation
tags:
- key: "bun"
options: ["rel:belongs", "join:author_id=id"]| Value | Description |
|---|---|
$SnakeCase |
Convert to snake_case |
$CamelCase |
Convert to camelCase |
#field_name |
Use literal value |
Define arbitrary Go structs that are not backed by a database table. Useful for:
- JSON/JSONB column types (value objects, embedded documents)
- Configuration objects
- API request/response types
- Any Go struct with Scan/Value methods for database scanning
custom:
# Struct-level comment (rendered above the type declaration)
- name: "Config"
comment: "Application configuration stored as JSONB"
fields:
- name: "Theme"
type: "string"
comment: "UI theme (light/dark)" # Field-level comment
- name: "Locale"
type: "string"
comment: "User locale"
- name: "Description"
type: "string"
comment: "Multi-line description\nrendered above the field\nline by line"
- name: "RefreshInterval"
type: "int"
comment: "Auto-refresh interval in seconds"
- name: "Metadata"
fields:
- name: "Tags"
type: "[]string"
- name: "Owner"
type: "string"
tags:
- key: "json"
name: "owner"
options: ["omitempty"] # Custom tag with optionsField tags support the same tag name transformations as table fields ($SnakeCase, $CamelCase, #literal).
You can use custom templates. The following data is passed to templates:
type Model struct {
Version string // bake version
Module string // module path
Package string // package name
Imports [][]string // imports
BunModel string // bun.BaseModel
Table string // table name
Model string // model name
Alias string // model alias
Comments []string // model comments
Fields []*Field // fields
Timezone string // timezone
CreatedAtType string // created_at type
UpdatedAtType string // updated_at type
DeletedAtType string // deleted_at type
MaxFieldLength int // max field length
MaxNullableLength int // max nullable length
MaxStringLength int // max string length
MaxNumericLength int // max numeric length
MaxOrderedLength int // max ordered length
MaxOrderedNonStringLength int // max ordered non-string length (numeric + time)
MaxEquatableLength int // max equatable length
MaxRelationLength int // max relation length
MaxArithmeticLength int // max arithmetic length (non-pk numeric)
MaxTimeLength int // max time length
}
type Field struct {
Imports []string // field imports
Name string // field name
AlignedName string // aligned field name
Type string // Go type
AlignedType string // aligned type
Tag string // field tags
AlignedTag string // aligned tag
Comments []string // field comments
ColumnName string // database column name
Kind string // field kind: NUMERIC, STRING, TIME, etc.
IsPrimary bool // is primary key
IsNullable bool // is nullable
IsCustom bool // is custom field
IsRelation bool // is relation field
}When using the custom template (default: custom.tmpl), the following data is passed:
type CustomStruct struct {
Version string // bake version
Package string // package name
Module string // module path
Imports [][]string // grouped imports
Name string // struct name (PascalCase)
Comment []string // struct-level comment lines
Fields []*StructField // fields in this struct
}
type StructField struct {
Name string // Go field name (PascalCase)
AlignedName string // Name padded to max width
GoType string // Go type
AlignedType string // GoType padded to max width
Tag string // Struct tag (including backticks)
AlignedTag string // Tag padded to max width
Comment []string // Multi-line comment
}
Generated features:
- **Field alignment** — Names, types, and tags are aligned with padding
- **Multi-line comments** — Rendered before the field, tag alignment is skipped for fields with multi-line comments
- **Comment groups** — Multi-line comment fields separate struct fields into alignment groups
- **Scan/Value** — Each struct gets `Scan(src any)` and `Value() (driver.Value, error)` methods for `database/sql` compatibility
## Type Mappings
### MySQL
| MySQL Type | Go Type |
| ------------------- | --------------- |
| tinyint(1) | bool |
| tinyint | int8 / uint8 |
| smallint | int16 / uint16 |
| int | int32 / uint32 |
| bigint | int64 / uint64 |
| float | float32 |
| double | float64 |
| decimal | decimal.Decimal |
| varchar, text | string |
| blob | []byte |
| datetime, timestamp | time.Time |
| json | json.RawMessage |
| enum, set | string |
### PostgreSQL
| PostgreSQL Type | Go Type |
| --------------------- | --------------------------------------- |
| int2 | int16 |
| int4 | int32 |
| int8 | int64 |
| float4 | float32 |
| float8 | float64 |
| numeric, decimal | decimal.Decimal |
| bool | bool |
| text, varchar | string |
| bytea | []byte |
| timestamp, date, time | time.Time |
| json, jsonb | json.RawMessage |
| uuid | uuid.UUID |
| inet, cidr | net.IP |
| interval | time.Duration |
| ARRAY | []string, []int32, []int64, []uuid.UUID |
## Generated Bun Tags
bake automatically generates bun struct tags for each column based on the database schema.
### Index Tags
| Scenario | Generated Tag | Description |
|----------|--------------|-------------|
| Primary key | `pk,autoincrement` | Primary key column |
| Single-column unique index | `unique` | Column has a unique constraint |
| Composite unique index | `unique:index_name` | Column is part of a multi-column unique index |
Example for a composite unique index on `(start_at, end_at)`:
```go
StartAt time.Time `bun:"start_at,unique:idx_unique_range,notnull"`
EndAt time.Time `bun:"end_at,unique:idx_unique_range,notnull"`| Property | Tag | Condition |
|---|---|---|
notnull |
Non-nullable column | IS_NOT_NULL or NOT NULL |
nullzero |
Nullable column | IS_NULL or nullable |
default:value |
Has default value | Column has a default |
soft_delete |
Soft delete column | Column name is deleted_at |
type:decimal(M,N) |
Decimal type | MySQL/PostgreSQL decimal columns |
bake automatically detects foreign key relationships from your database schema and generates the appropriate bun relation tags.
When a column has a foreign key constraint:
-- posts.user_id references users.id
ALTER TABLE posts ADD CONSTRAINT fk_posts_user_id
FOREIGN KEY (user_id) REFERENCES users(id);bake will automatically:
- On
poststable: GenerateUser *Userfield withrel:belongs-to - On
userstable: GeneratePosts []*Postfield withrel:has-many
For the posts table with user_id foreign key:
// Post struct
type Post struct {
bun.BaseModel `bun:"table:posts"`
ID int64 `bun:"id,pk,autoincrement"`
UserID int64 `bun:"user_id,notnull"`
Title string `bun:"title,notnull"`
User *User `bun:"user,rel:belongs-to,join:user_id=id"`
}
// User struct (auto-generated reverse relation)
type User struct {
bun.BaseModel `bun:"table:users"`
ID int64 `bun:"id,pk,autoincrement"`
Name string `bun:"name,notnull"`
Posts []*Post `bun:"posts,rel:has-many,join:id=user_id"`
}You can still manually configure relations using the customs configuration. Manual configuration takes precedence over automatic detection.
Custom structs allow you to define Go structs that are not tied to database tables. They are generated with Scan and Value methods for database/sql compatibility, making them ideal for JSON/JSONB column types.
Define custom structs in your bake.gen.yaml:
output:
dir: "model"
package: "model"
module: "github.com/user/project"
custom:
- name: "Config"
comment: "Application configuration stored as JSONB"
fields:
- name: "Theme"
type: "string"
comment: "UI theme (light/dark)"
- name: "Notifications"
type: "bool"
comment: "Enable push notifications"
- name: "Description"
type: "string"
comment: "A detailed description\nwith multiple lines"Running bake generates one file per custom struct (e.g., model/config.gen.go):
// Code generated by bake. DO NOT EDIT.
// version: v0.2.1
package model
import (
"database/sql/driver"
"encoding/json"
"errors"
)
// Application configuration stored as JSONB
type Config struct {
// A detailed description
// with multiple lines
Description string `json:"description,omitempty"`
Notifications bool `json:"notifications,omitempty"` // Enable push notifications
Theme string `json:"theme,omitempty"` // UI theme (light/dark)
}
func (o *Config) Scan(src any) error {
if src == nil {
return nil
}
switch v := src.(type) {
case []byte:
return json.Unmarshal(v, o)
case string:
return json.Unmarshal([]byte(v), o)
default:
return errors.New("unsupported type")
}
}
func (o Config) Value() (driver.Value, error) {
return json.Marshal(o)
}Fields within the same comment group are aligned for readability:
| Group condition | Alignment behavior |
|---|---|
| Consecutive single-line comments | Names/types/tags are aligned to the widest value in the group |
| Multi-line comment field | The field's tag is not padded; creates a new alignment group |
| No comment | Rendered with // suffix and aligned normally |
See examples/mysql/ or examples/postgres/ for complete working examples with custom structs integrated alongside database models.
go test ./...go build ./cmd/bakeApache License 2.0 - see LICENSE file