Skip to main content
A has one association establishes a one-to-one relationship between two models. Unlike belongs to, the foreign key lives on the associated model’s table, not on the declaring model.

Struct definition

type User struct {
  gorm.Model
  CreditCard CreditCard
}

type CreditCard struct {
  gorm.Model
  Number string
  UserID uint  // foreign key — references users.id
}
GORM infers the has one relationship from the struct field type. The foreign key on CreditCard is UserID by convention (<OwnerType>ID).

Override the foreign key

Use the foreignKey tag to use a different field name on the associated model:
type User struct {
  gorm.Model
  CreditCard CreditCard `gorm:"foreignKey:UserRefer"`
}

type CreditCard struct {
  gorm.Model
  Number    string
  UserRefer uint
}

Override references

By default GORM uses the owner’s primary key as the reference. Point to a different field with references:
type User struct {
  gorm.Model
  MemberNumber string     `gorm:"unique"`
  CreditCard   CreditCard `gorm:"foreignKey:UserMemberNumber;references:MemberNumber"`
}

type CreditCard struct {
  gorm.Model
  Number           string
  UserMemberNumber string
}

Create with a HasOne association

When you create a User, GORM creates the associated CreditCard in the same transaction if the struct is populated:
user := User{
  CreditCard: CreditCard{Number: "4111-1111-1111-1111"},
}
db.Create(&user)
// INSERT INTO users DEFAULT VALUES;
// INSERT INTO credit_cards (number, user_id) VALUES ('4111-1111-1111-1111', 1);
To skip saving the association, use Select or Omit:
db.Select("Name").Create(&user)    // only save Name field, skip associations
db.Omit("CreditCard").Create(&user) // skip CreditCard association

Query with Preload

Eagerly load the associated record alongside the owner:
var users []User
db.Preload("CreditCard").Find(&users)
// SELECT * FROM users;
// SELECT * FROM credit_cards WHERE user_id IN (1, 2, 3);
Load a single user:
var user User
db.Preload("CreditCard").First(&user, 1)

Conditional preload

Filter associated records with a condition string or a function:
// Only preload active credit cards
db.Preload("CreditCard", "number LIKE ?", "4111%").Find(&users)

// Using a function
db.Preload("CreditCard", func(db *gorm.DB) *gorm.DB {
  return db.Where("number IS NOT NULL")
}).Find(&users)

Query with Joins

Joins loads the association using a LEFT JOIN in a single SQL statement:
var users []User
db.Joins("CreditCard").Find(&users)
// SELECT users.*, credit_cards.id AS "CreditCard__id", credit_cards.number AS "CreditCard__number"
// FROM users LEFT JOIN credit_cards ON credit_cards.user_id = users.id;
Use InnerJoins instead of Joins when you only want users that have a credit card:
db.InnerJoins("CreditCard").Find(&users)

Update a HasOne association

Use Association mode to replace the current associated record:
newCard := CreditCard{Number: "5500-0000-0000-0004"}
db.Model(&user).Association("CreditCard").Replace(&newCard)
To remove the association without deleting the record (sets the foreign key to NULL):
db.Model(&user).Association("CreditCard").Clear()

Constraints

Define referential actions on the foreign key constraint:
type User struct {
  gorm.Model
  CreditCard CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
If you use OnDelete:CASCADE, deleting a User will also delete their CreditCard at the database level. Make sure this matches your application’s intent.

Build docs developers (and LLMs) love