Binds a GraphQL type to a jOOQ-modelled database table so the generator can project columns, build joins, and emit mutations against it.

SDL signature

directive @table(name: String) on OBJECT | INPUT_OBJECT | INTERFACE

The INPUT_OBJECT location is deprecated: the directive is accepted there and then ignored, with a build warning per usage, and will be rejected in a future release. See Deprecated on input types below.

Parameters

Name Type Default Description

name

String

type name (case-insensitive)

The jOOQ table identifier. Must match the SQL identifier as it appears in jOOQ’s catalog. Omit when the GraphQL type name already equals the table name. For jOOQ catalogs that span multiple schemas, the value can be qualified as "schema.table" to scope the lookup; an unqualified value is only accepted when exactly one schema in the catalog contains a table with that name.

Canonical example

The tutorial’s Customer type binds to the customer table:

type Customer implements Node @table(name: "customer") @node {
    customerId: Int!     @field(name: "CUSTOMER_ID")
    firstName:  String!  @field(name: "FIRST_NAME")
    address:    Address  @reference(path: [{key: "customer_address_id_fkey"}])
}

A query that selects customers { firstName } produces a SELECT customer.first_name against this binding. Because the type carries @table, every @field-annotated column inside resolves against the customer table by default; nested types like Address re-bind via their own @table and join to Customer through @reference.

Deprecated on input types

Applying @table to an input (INPUT_OBJECT) is deprecated. The directive is accepted and then ignored: its name: argument is never read, and the input classifies exactly as the same input without it would. Every usage earns a build warning naming the type, and the location will be rejected outright in a future release. Remove it now. @table on OBJECT and INTERFACE is unaffected.

Because the directive is ignored rather than honoured, an input whose @table names a different table from the one its consuming field resolves is not migrated silently-but-correctly: the declared table is discarded and the consumer’s is used. The build warning is the only signal, so read it rather than assuming the two agreed.

An input type never needed its own table fact: an input’s fields resolve against each consuming field’s table, and an input reused across consumers resolves per-consumer. What to do instead depends on the consumer:

  • Filters and lookup arguments need no directive at all. Remove @table; the fields resolve against the consuming field’s return-type table.

  • @mutation(typeName: DELETE) names its write target with @mutation(table: "…") on the field. A DELETE cannot derive its table from the return type (the row is gone after the statement, so a @table return is not supported).

  • @mutation(typeName: INSERT) and UPDATE derive the write target from the field’s return type: a @table return, or a carrier payload whose data field is a @table element. For an encoded-ID / scalar return that names no table (e.g. createFilm(…​): ID), name it with @mutation(table: "…") on the field.

Constraints

  • The name parameter must resolve to a real jOOQ table; the generator fails the build with an unclassified-type error if the catalog has no matching Table class. Use the same case the jOOQ generator emits (typically uppercase for PostgreSQL identifiers, but follow your project’s catalog).

  • When omitted, the generator looks up the jOOQ table by GraphQL type name (case-insensitive). A type named Customer therefore resolves to the customer table without explicit configuration.

  • Containing fields default to the type’s table for column lookup. A nested @table re-binds; an @reference-annotated field hops into the joined table for the duration of that field’s subquery.

  • For multi-schema catalogs, an unqualified name: must be unique across schemas. When the same bare name exists in two or more schemas (event in public and archive, say), the build fails with @table(name: 'event') is ambiguous: defined in schemas [public, archive]; qualify as 'public.event', 'archive.event'. Disambiguate by qualifying explicitly: @table(name: "public.event"). Single-schema consumers see no change; only collision sites are forced to qualify. A genuinely missing name (no schema contains it) falls through to the standard table 'X' could not be resolved in the jOOQ catalog rejection with a Levenshtein-ranked candidate hint.

See also

  • Tutorial page 2: The starter schema introduces @table and @field together.

  • @field for column-level binding inside a @table-bound type.

  • @reference for explicit join paths between two @table-bound types.

  • @mutation for how a write names its target table (return-derived, or @mutation(table:) on the field).