pg-flux

Codegen

Codegen overview

#Codegen

pg-flux generates application-language type definitions for every catalog object that has a row shape. Go structs, TypeScript interfaces, enum constants, composite types, domains, views (with inferred column types), function parameters, and procedure parameters — all derived from the same schema model that powers migrations.

Shell
pg-flux gen --lang go,ts

Two opt-in flavors (every option configurable per output):

Shell
pg-flux gen init   # scaffold .pg-flux-codegen.yml with every option documented
pg-flux gen        # respects the config; multi-output capable
pg-flux gen --check  # exit 1 if generated files are stale (CI gate)

#What gets generated

PG object Go TypeScript Python Rust
Table type User struct { … } interface User { … } class User(BaseModel) + UserCreate + UserUpdate pub struct User { … }
View / matview struct with typed fields interface with typed fields class UserView(BaseModel) — all fields Optional pub struct UserView { … } — all fields Option
Enum type Role string + constants union / const-object / ts-enum class Role(str, Enum) pub enum Role with sqlx::Type
Composite type struct interface class Address(BaseModel) pub struct Address
Domain type alias type alias NewType("EmailAddress", str) newtype struct pub struct EmailAddress(pub String)
Function <Name>Params + <Name>Result <Name>Params + <Name>Result TypedDict params + BaseModel result <Name>Params struct + result type
Procedure <Name>Params only <Name>Params only TypedDict params only <Name>Params struct only

Sequences, indexes, triggers, policies aren't generated — they don't have row shapes. (See Function signatures → for the rationale.)

#Per-output options

The config file or CLI can drive every shape decision:

Option Choices Applies to
column_case snake (default) / camel / pascal both
readonly none / identity / generated / defaults / all both
bigint_as bigint (default) / number / string TS
date_as Date (default) / string / temporal TS
null_style union (default) / undefined / optional TS
enum_style union (default) / const-object / ts-enum TS
branded_ids bool TS
insert_update_helpers bool TS
validators zod / "" TS
orm_tags sqlx / gorm / bun / ent / "" Go
omitempty nullable / defaults / all / "" Go
functions bool — emit function param/result types both
json_shapes map of "schema.table.column" → TS type TS
type_overrides per PG type → custom language type both
include_tables / exclude_tables / exclude_schemas globs both

#Example: multi-target config

YAML
# .pg-flux-codegen.yml
outputs:
  - lang: go
    out: ./internal/db
    package: db
    orm_tags: sqlx
    omitempty: nullable
    functions: true
    type_overrides:
      numeric: github.com/shopspring/decimal.Decimal

  - lang: ts
    out: ./apps/web/src/db
    column_case: camel
    bigint_as: number
    date_as: string
    null_style: optional
    enum_style: const-object
    branded_ids: true
    insert_update_helpers: true
    validators: zod
    functions: true

  - lang: ts
    out: ./apps/mobile/src/db
    column_case: camel
    bigint_as: string         # mobile prefers strings for IDs
    date_as: Date
    null_style: union

One schema, three outputs, all idiomatic for their stack.

#Comment hints

Add per-column overrides via PG comments:

SQL
COMMENT ON COLUMN posts.metadata IS 'pg-flux: tstype={ source: string; ip?: string } gotype=*postsmeta.Metadata';

Tokens:

  • gotype=... — fully-qualified Go type (may include import path)
  • tstype=... — verbatim TS type expression
  • Anything before pg-flux: becomes the field's documentation comment

The tokenizer balances braces/brackets/parens, so complex type expressions don't need quoting:

SQL
pg-flux: tstype=Array<{ k: string; v: number }> gotype=map[string][]byte

#See also