Skip to content

Index order in generated models is non-deterministic #1409

@tomoropy

Description

@tomoropy

Index order in generated models is non-deterministic

Problem

When generating GORM models using gorm.io/gen, the order of indexes in the generated gorm tags is non-deterministic. This causes the generated code to differ between CI and local environments, even when the database schema is identical.

Example

The same database schema can generate different code:

Run 1:

TenantID string `gorm:"column:tenant_id;type:uuid;not null;index:idx_payout_tenant_id,priority:1;index:idx_payout_tenant_payment_at,priority:2;comment:tenant ID" json:"tenant_id"`

Run 2:

TenantID string `gorm:"column:tenant_id;type:uuid;not null;index:idx_payout_tenant_payment_at,priority:2;index:idx_payout_tenant_id,priority:1;comment:tenant ID" json:"tenant_id"`

The indexes are functionally equivalent, but the order differs, causing unnecessary diffs in version control and CI failures.

Root Cause

The issue occurs in internal/model/tbl_column.go in the buildGormTag() method. When iterating over c.Indexes, the order depends on how PostgreSQL returns index information, which is based on OID (Object ID) order. This order can vary between database instances or even between queries on the same database.

The relevant code:

for _, idx := range c.Indexes {
    // ...
    tag.Append(field.TagKeyGormIndex, fmt.Sprintf("%s,priority:%d", idx.Name(), idx.Priority))
}

Since c.Indexes is populated from PostgreSQL's system catalogs without explicit ordering, the iteration order is non-deterministic.

Environment

  • GORM gen version: v0.3.27
  • PostgreSQL version: 17.7
  • Go version: 1.25.0
  • Database: PostgreSQL

Expected Behavior

The index order in generated models should be deterministic and consistent across all environments. Ideally, indexes should be sorted alphabetically by name to ensure consistent output.

Proposed Solution

Sort the indexes by name before iterating over them in the buildGormTag() method. This ensures that the generated code is always consistent, regardless of the order returned by PostgreSQL.

Impact

This issue affects:

  • CI/CD pipelines that check if generated code is up-to-date
  • Teams working on the same codebase where generated files are committed
  • Any workflow that relies on deterministic code generation

Workaround

Currently, we work around this by:

  1. Using a post-processing script to normalize index order after generation
  2. Commenting out the generation check in CI until the issue is resolved

However, this is not ideal and adds maintenance overhead.

Additional Context

This issue is particularly noticeable when:

  • Multiple indexes exist on the same column
  • Working with composite indexes
  • Running migrations in different environments (CI vs local)

The problem becomes more apparent when using CI to verify that generated code matches the current database schema, as the check fails due to non-functional differences in index order.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions