Fields

    Fields are returned from the schema using the Fields method. For example:

    All fields are required by default, and can be set to optional using the Optional method.

    Types

    The following types are currently supported by the framework:

    • All Go numeric types. Like int, uint8, float64, etc.
    • bool
    • string
    • time.Time
    • UUID
    • []byte (SQL only).
    • JSON (SQL only).
    • Enum (SQL only).
    • Other (SQL only).
    1. package schema
    2. import (
    3. "time"
    4. "net/url"
    5. "github.com/google/uuid"
    6. "entgo.io/ent"
    7. "entgo.io/ent/schema/field"
    8. )
    9. // User schema.
    10. type User struct {
    11. ent.Schema
    12. }
    13. // Fields of the user.
    14. func (User) Fields() []ent.Field {
    15. return []ent.Field{
    16. field.Int("age").
    17. Positive(),
    18. field.Float("rank").
    19. Optional(),
    20. field.Bool("active").
    21. Default(false),
    22. field.String("name").
    23. Unique(),
    24. field.Time("created_at").
    25. Default(time.Now),
    26. field.JSON("url", &url.URL{}).
    27. Optional(),
    28. field.JSON("strings", []string{}).
    29. Optional(),
    30. field.Enum("state").
    31. Values("on", "off").
    32. Optional(),
    33. field.UUID("uuid", uuid.UUID{}).
    34. Default(uuid.New),
    35. }
    36. }

    To read more about how each type is mapped to its database-type, go to the section.

    ID Field

    The id field is builtin in the schema and does not need declaration. In SQL-based databases, its type defaults to int (but can be changed with a ) and auto-incremented in the database.

    In order to configure the id field to be unique across all tables, use the WithGlobalUniqueID option when running schema migration.

    If a different configuration for the id field is needed, or the id value should be provided on entity creation by the application (e.g. UUID), override the builtin id configuration. For example:

    1. // Fields of the Group.
    2. func (Group) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.Int("id").
    5. StructTag(`json:"oid,omitempty"`),
    6. }
    7. }
    8. // Fields of the Blob.
    9. func (Blob) Fields() []ent.Field {
    10. return []ent.Field{
    11. field.UUID("id", uuid.UUID{}).
    12. Default(uuid.New).
    13. StorageKey("oid"),
    14. }
    15. }
    16. // Fields of the Pet.
    17. func (Pet) Fields() []ent.Field {
    18. return []ent.Field{
    19. field.String("id").
    20. MaxLen(25).
    21. NotEmpty().
    22. Unique().
    23. Immutable(),
    24. }
    25. }

    If you need to set a custom function to generate IDs, you can use DefaultFunc to specify a function which will always be ran when the resource is created. See the for more information.

    1. // Fields of the User.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.Int64("id").
    5. DefaultFunc(func() int64 {
    6. // An example of a dumb ID generator - use a production-ready alternative instead.
    7. return time.Now().Unix() << 8 | atomic.AddInt64(&counter, 1) % 256
    8. }),
    9. }
    10. }

    Database Type

    Each database dialect has its own mapping from Go type to database type. For example, the MySQL dialect creates float64 fields as double columns in the database. However, there is an option to override the default behavior using the SchemaType method.

    1. package schema
    2. import (
    3. "entgo.io/ent"
    4. "entgo.io/ent/dialect"
    5. "entgo.io/ent/schema/field"
    6. )
    7. // Card schema.
    8. type Card struct {
    9. ent.Schema
    10. }
    11. // Fields of the Card.
    12. func (Card) Fields() []ent.Field {
    13. return []ent.Field{
    14. field.Float("amount").
    15. SchemaType(map[string]string{
    16. dialect.MySQL: "decimal(6,2)", // Override MySQL.
    17. dialect.Postgres: "numeric", // Override Postgres.
    18. }),
    19. }
    20. }

    Go Type

    The default type for fields are the basic Go types. For example, for string fields, the type is string, and for time fields, the type is time.Time. The GoType method provides an option to override the default ent type with a custom one.

    The custom type must be either a type that is convertible to the Go basic type, or a type that implements the ValueScanner interface.

    1. package schema
    2. import (
    3. "database/sql"
    4. "entgo.io/ent"
    5. "entgo.io/ent/dialect"
    6. "entgo.io/ent/schema/field"
    7. "github.com/shopspring/decimal"
    8. )
    9. // Amount is a custom Go type that's convertible to the basic float64 type.
    10. type Amount float64
    11. // Card schema.
    12. type Card struct {
    13. ent.Schema
    14. }
    15. // Fields of the Card.
    16. func (Card) Fields() []ent.Field {
    17. return []ent.Field{
    18. field.Float("amount").
    19. GoType(Amount(0)),
    20. field.String("name").
    21. Optional().
    22. // A ValueScanner type.
    23. GoType(&sql.NullString{}),
    24. field.Enum("role").
    25. // A convertible type to string.
    26. GoType(role.Role("")),
    27. field.Float("decimal").
    28. // A ValueScanner type mixed with SchemaType.
    29. GoType(decimal.Decimal{}).
    30. dialect.MySQL: "decimal(6,2)",
    31. dialect.Postgres: "numeric",
    32. }),
    33. }
    34. }

    Other Field

    Other represents a field that is not a good fit for any of the standard field types. Examples are a Postgres Range type or Geospatial type

    1. package schema
    2. import (
    3. "entgo.io/ent"
    4. "entgo.io/ent/dialect"
    5. "entgo.io/ent/schema/field"
    6. )
    7. // User schema.
    8. type User struct {
    9. ent.Schema
    10. }
    11. // Fields of the User.
    12. func (User) Fields() []ent.Field {
    13. return []ent.Field{
    14. field.Other("duration", &pgtype.Tstzrange{}).
    15. SchemaType(map[string]string{
    16. dialect.Postgres: "tstzrange",
    17. }),
    18. }
    19. }

    Default Values

    Non-unique fields support default values using the Default and UpdateDefault methods. You can also specify DefaultFunc instead to have a custom generator.

    1. // Fields of the User.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.Time("created_at").
    5. Default(time.Now),
    6. field.Time("updated_at").
    7. Default(time.Now).
    8. UpdateDefault(time.Now),
    9. field.String("name").
    10. Default("unknown"),
    11. field.String("cuid").
    12. DefaultFunc(cuid.New),
    13. field.JSON("dirs", []http.Dir{}).
    14. Default([]http.Dir{"/tmp"}),
    15. }
    16. }

    SQL-specific expressions like function calls can be added to default value configuration using the :

    1. // Fields of the User.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. // Add a new field with CURRENT_TIMESTAMP
    5. // as a default value to all previous rows.
    6. field.Time("created_at").
    7. Default(time.Now).
    8. Annotations(&entsql.Annotation{
    9. Default: "CURRENT_TIMESTAMP",
    10. }),
    11. }
    12. }

    In case your DefaultFunc is also returning an error, it is better to handle it properly using schema-hooks. See for more information.

    A field validator is a function from type func(T) error that is defined in the schema using the Validate method, and applied on the field value before creating or updating the entity.

    1. package schema
    2. import (
    3. "errors"
    4. "regexp"
    5. "strings"
    6. "time"
    7. "entgo.io/ent"
    8. "entgo.io/ent/schema/field"
    9. )
    10. // Group schema.
    11. type Group struct {
    12. ent.Schema
    13. }
    14. // Fields of the group.
    15. func (Group) Fields() []ent.Field {
    16. return []ent.Field{
    17. field.String("name").
    18. Match(regexp.MustCompile("[a-zA-Z_]+$")).
    19. Validate(func(s string) error {
    20. if strings.ToLower(s) == s {
    21. return errors.New("group name must begin with uppercase")
    22. }
    23. return nil
    24. }),
    25. }
    26. }

    Here is another example for writing a reusable validator:

    Built-in Validators

    The framework provides a few built-in validators for each type:

    • Numeric types:

      • Positive()
      • Negative()
      • NonNegative()
      • Min(i) - Validate that the given value is > i.
      • Max(i) - Validate that the given value is < i.
      • Range(i, j) - Validate that the given value is within the range [i, j].
    • string

      • MinLen(i)
      • MaxLen(i)
      • Match(regexp.Regexp)
      • NotEmpty
    • []byte

      • MaxLen(i)
      • MinLen(i)
      • NotEmpty

    Optional

    Optional fields are fields that are not required in the entity creation, and will be set to nullable fields in the database. Unlike edges, fields are required by default, and setting them to optional should be done explicitly using the Optional method.

    1. // Fields of the user.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("required_name"),
    5. field.String("optional_name").
    6. Optional(),
    7. }
    8. }

    Nillable

    Sometimes you want to be able to distinguish between the zero value of fields and nil; for example, if the database column contains 0 or NULL. The Nillable option exists exactly for this.

    If you have an Optional field of type T, setting it to Nillable will generate a struct field with type *T. Hence, if the database returns NULL for this field, the struct field will be nil. Otherwise, it will contain a pointer to the actual data.

    For example, given this schema:

    1. // Fields of the user.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("required_name"),
    5. field.String("optional_name").
    6. Optional(),
    7. field.String("nillable_name").
    8. Optional().
    9. Nillable(),
    10. }
    11. }

    The generated struct for the User entity will be as follows:

    1. // ent/user.go
    2. package ent
    3. // User entity.
    4. type User struct {
    5. RequiredName string `json:"required_name,omitempty"`
    6. OptionalName string `json:"optional_name,omitempty"`
    7. NillableName *string `json:"nillable_name,omitempty"`
    8. }

    Immutable

    Immutable fields are fields that can be set only in the creation of the entity. i.e., no setters will be generated for the entity updater.

    1. // Fields of the user.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("name"),
    5. field.Time("created_at").
    6. Default(time.Now).
    7. Immutable(),
    8. }
    9. }

    Uniqueness

    Fields can be defined as unique using the Unique method. Note that unique fields cannot have default values.

    1. // Fields of the user.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("name"),
    5. field.String("nickname").
    6. Unique(),
    7. }
    8. }

    Storage Key

    Custom storage name can be configured using the StorageKey method. It’s mapped to a column name in SQL dialects and to property name in Gremlin.

    1. // Fields of the user.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("name").
    5. StorageKey("old_name"),
    6. }
    7. }

    Indexes can be defined on multi fields and some types of edges as well. However, you should note, that this is currently an SQL-only feature.

    Read more about this in the Indexes section.

    Struct Tags

    Custom struct tags can be added to the generated entities using the StructTag method. Note that if this option was not provided, or provided and did not contain the json tag, the default json tag will be added with the field name.

    1. // Fields of the user.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("name").
    5. StructTag(`gqlgen:"gql_name"`),
    6. }
    7. }

    Additional Struct Fields

    By default, ent generates the entity model with fields that are configured in the schema.Fields method. For example, given this schema configuration:

    1. // User schema.
    2. }
    3. // Fields of the user.
    4. func (User) Fields() []ent.Field {
    5. return []ent.Field{
    6. field.Int("age").
    7. Optional().
    8. Nillable(),
    9. field.String("name").
    10. StructTag(`gqlgen:"gql_name"`),
    11. }
    12. }
    1. // User is the model entity for the User schema.
    2. type User struct {
    3. // Age holds the value of the "age" field.
    4. Age *int `json:"age,omitempty"`
    5. // Name holds the value of the "name" field.
    6. Name string `json:"name,omitempty" gqlgen:"gql_name"`
    7. }

    In order to add additional fields to the generated struct that are not stored in the database, use . For example:

    The generated model will be as follows:

    1. // User is the model entity for the User schema.
    2. type User struct {
    3. // Age holds the value of the "age" field.
    4. Age *int `json:"age,omitempty"`
    5. // Name holds the value of the "name" field.
    6. Name string `json:"name,omitempty" gqlgen:"gql_name"`
    7. // StaticField defined by template.
    8. StaticField string `json:"static,omitempty"`
    9. }

    Sensitive Fields

    String fields can be defined as sensitive using the Sensitive method. Sensitive fields won’t be printed and they will be omitted when encoding.

    Note that sensitive fields cannot have struct tags.

    1. // User schema.
    2. type User struct {
    3. ent.Schema
    4. }
    5. // Fields of the user.
    6. func (User) Fields() []ent.Field {
    7. return []ent.Field{
    8. field.String("password").
    9. Sensitive(),
    10. }
    11. }

    Enum Fields

    The Enum builder allows creating enum fields with a list of permitted values.

    1. // Fields of the User.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("first_name"),
    5. field.String("last_name"),
    6. field.Enum("size").
    7. Values("big", "small"),
    8. }
    9. }

    When a custom GoType is being used, it is must be convertible to the basic string type or it needs to implement the interface.

    The EnumValues interface is also required by the custom Go type to tell Ent what are the permitted values of the enum.

    The following example shows how to define an Enum field with a custom Go type that is convertible to string:

    1. // Fields of the User.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("first_name"),
    5. field.String("last_name"),
    6. // A convertible type to string.
    7. field.Enum("shape").
    8. GoType(property.Shape("")),
    9. }
    10. }

    Implement the interface.

    1. package property
    2. type Shape string
    3. const (
    4. Triangle Shape = "TRIANGLE"
    5. Circle Shape = "CIRCLE"
    6. )
    7. // Values provides list valid values for Enum.
    8. func (Shape) Values() (kinds []string) {
    9. for _, s := range []Shape{Triangle, Circle} {
    10. kinds = append(kinds, string(s))
    11. }
    12. return
    13. }

    The following example shows how to define an Enum field with a custom Go type that is not convertible to string, but it implements the ValueScanner interface:

    1. // Fields of the User.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("first_name"),
    5. field.String("last_name"),
    6. // Add conversion to and from string
    7. field.Enum("level").
    8. GoType(property.Level(0)),
    9. }
    10. }

    Implement also the interface.

    1. package property
    2. import "database/sql/driver"
    3. type Level int
    4. const (
    5. Unknown Level = iota
    6. Low
    7. High
    8. )
    9. func (p Level) String() string {
    10. switch p {
    11. case Low:
    12. return "LOW"
    13. case High:
    14. return "HIGH"
    15. default:
    16. return "UNKNOWN"
    17. }
    18. }
    19. // Values provides list valid values for Enum.
    20. func (Level) Values() []string {
    21. return []string{Unknown.String(), Low.String(), High.String()}
    22. }
    23. // Value provides the DB a string from int.
    24. func (p Level) Value() (driver.Value, error) {
    25. return p.String(), nil
    26. }
    27. // Scan tells our code how to read the enum into our type.
    28. func (p *Level) Scan(val interface{}) error {
    29. var s string
    30. switch v := val.(type) {
    31. case nil:
    32. return nil
    33. case string:
    34. s = v
    35. case []uint8:
    36. s = string(v)
    37. }
    38. switch s {
    39. case "LOW":
    40. *p = Low
    41. case "HIGH":
    42. *p = High
    43. default:
    44. *p = Unknown
    45. }
    46. return nil
    47. }

    Combining it all together:

    1. // Fields of the User.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("first_name"),
    5. field.String("last_name"),
    6. field.Enum("size").
    7. Values("big", "small"),
    8. // A convertible type to string.
    9. field.Enum("shape").
    10. GoType(property.Shape("")),
    11. // Add conversion to and from string.
    12. field.Enum("level").
    13. GoType(property.Level(0)),
    14. }
    15. }

    After code generation usage is trivial:

    1. client.User.Create().
    2. SetFirstName("John").
    3. SetLastName("Dow").
    4. SetSize(user.SizeSmall).
    5. SetShape(property.Triangle).
    6. SetLevel(property.Low).
    7. SaveX(context.Background())
    8. john := client.User.Query().FirstX(context.Background())
    9. // User(id=1, first_name=John, last_name=Dow, size=small, shape=TRIANGLE, level=LOW)

    Annotations

    Annotations is used to attach arbitrary metadata to the field object in code generation. Template extensions can retrieve this metadata and use it inside their templates.

    Note that the metadata object must be serializable to a JSON raw value (e.g. struct, map or slice).

    Read more about annotations and their usage in templates in the .

    Naming Convention

    By convention field names should use snake_case. The corresponding struct fields generated by ent will follow the Go convention of using PascalCase. In cases where PascalCase is desired, you can do so with the or StructTag methods.