Names the underlying-binding target for a GraphQL slot. The axis is determined by the directive site: column on a field or input field, column on a filter argument, database string (or Java enum constant) on an enum value.

SDL signature

directive @field(name: String!) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE

Parameters

Name Type Default Description

name

String!

(required)

The target identifier. Resolves as a column name on FIELD_DEFINITION, ARGUMENT_DEFINITION, and INPUT_FIELD_DEFINITION; resolves as the database string (or, where applicable, the Java enum constant) on ENUM_VALUE. The literal value $source is also admitted at one specific site; see Root-value sigil: $source.

Canonical example

The tutorial’s Customer type uses @field on every scalar to map GraphQL camelCase to PostgreSQL snake_case:

type Customer @table(name: "customer") {
    firstName:  String!  @field(name: "FIRST_NAME")
    lastName:   String!  @field(name: "LAST_NAME")
    email:      String   @field(name: "EMAIL")
    activebool: Boolean! @field(name: "ACTIVEBOOL")
}

A query selecting firstName lastName produces SELECT customer.first_name AS "firstName", customer.last_name AS "lastName". The selection set drives the projection: ask only for firstName and the SELECT shrinks to one column.

On an argument, @field steers the column the filter binds to when the GraphQL argument name doesn’t match the column name. From Query.customers:

type Query {
    customers(active: Boolean @field(name: "ACTIVEBOOL")): [Customer!]!
}

Without the directive, the generator would look up a column called active on the customer table. Sakila’s customer table happens to have one (an unused integer flag), so the filter would silently bind to the wrong column. @field(name: "ACTIVEBOOL") pins it to the right one.

On an input field (a mutation), @field plays the same role:

input FilmCreateInput @table(name: "film") {
    title:      String! @field(name: "title")
    languageId: Int!    @field(name: "language_id")
}

The INSERT writes title and language_id; the GraphQL camelCase never reaches SQL.

On an enum value, @field maps the GraphQL value to the database string the value should encode as. See the mapping how-to for the enum case.

Root-value sigil: $source

In addition to a column or accessor name, the name argument admits one sigil literal: $source. It binds the SDL field to the upstream Java value taken as a whole, rather than to a member of it.

The sigil is admitted at exactly one site: the data field of a carrier-payload type returned by a @service-backed mutation. Anywhere else, @field(name: "$source") is rejected.

type Film @table(name: "film") {
    title: String
}

type FilmListPayload {
    films: [Film!] @field(name: "$source")
}

type Mutation {
    runFilms: FilmListPayload
        @service(service: {className: "com.example.FilmService", method: "getFilms"})
}

If FilmService.getFilms returns List<FilmRecord> (or Result<FilmRecord>), the films data field on the carrier payload is bound to that return value directly. The directive is a no-op confirmation of a binding the generator would otherwise infer implicitly; writing it makes the intent explicit and decouples the SDL slot name from the producer method’s signature.

The producer’s reflected return type must match the SDL element’s backing class. For a table-backed element, the producer must return the table’s record class (or List<RecordClass> / Result<RecordClass> when the SDL field is list-shaped); for a @record-backed element, the producer must return the declared record class with the same list-shape discipline. Mismatches fail the build with a typed message naming the producer and both types.

Unknown sigils are rejected at parse time: @field(name: "$foo") fails with Unknown sigil '$foo' on @field(name:); allowed: $source. The sigil at a non-admitted site fails with a message naming the only valid site.

Constraints

  • The name parameter is required; graphql-java rejects a no-arg @field at parse time.

  • The target identifier must resolve in the surrounding `@table’s jOOQ catalog. The generator fails the build if the column does not exist.

  • When the GraphQL slot name and the target identifier match (case-insensitively), the directive is unnecessary. The example schema applies it explicitly anyway because mismatches are common in PostgreSQL projects and explicit binding keeps drift detectable.

See also