Attach typed metadata directly to tables, columns, or any other schema resources, then render any file format from it with Go templates. The schema becomes the single source of truth for every spec that describes it: GraphQL types, OpenAPI fields, data catalog entries, and so on.
External tools rarely consume database schemas directly: a GraphQL server wants SDL, a REST gateway wants OpenAPI, a data catalog wants its own ingest format. Maintaining each spec alongside the schema means two sources of truth that drift the moment a column is renamed. The new template exporter collapses that: annotations attach metadata directly to tables, columns, or any other schema resources, and Go templates render whatever file format the consuming tool expects.
Define Annotation Types
Each annotation block in atlas.hcl is a type definition for metadata attached to a schema resource. The block name (table, column, or any other resource type) selects which resources may carry it; inside, it names the attributes the annotation accepts, their types, and any nested repeatable blocks. Atlas's type-checker enforces this definition at load time, so unknown attributes or values of the wrong type fail fast instead of slipping through to the template:
data "hcl_schema" "app" {path = "schema.hcl"annotation "table" {attr "type_name" {type = string}attr "description" {type = string}}annotation "column" {attr "graphql_type" {type = string}attr "deprecated" {type = string}}}
Schema resources then attach concrete values that conform to the declared type, and the same type-checker validates them on every load:
table "users" {schema = schema.publicannotation {type_name = "User"description = "A registered user"}column "id" {null = falsetype = intannotation {graphql_type = "ID!"}}column "name" {null = falsetype = textannotation {graphql_type = "String!"}}column "nickname" {null = truetype = textannotation {graphql_type = "String"deprecated = "Use name instead"}}primary_key {columns = [column.id]}}
Render with Templates
A bare template block runs once against the inspected schema. Adding on "table" runs it per table and exposes the table in the output name template:
exporter "template" "graphql" {template {src = "templates/schema.graphql.tmpl"name = "out/schema.graphql"}template {src = "templates/type.graphql.tmpl"on "table" {name = "out/types/{{ .Name }}.graphql"}}}env "local" {url = data.hcl_schema.app.urlexport {schema {inspect = exporter.template.graphql}}}
Inside the template, attr pulls annotations off any object and .Attr reads their values (use .Block for nested repeatable blocks):
{{- with $ann := attr .Object "annotation" -}}"""{{ $ann.Attr "description" }}"""type {{ $ann.Attr "type_name" }} {{{- range $c := $.Object.Columns }}{{- with $cann := attr $c "annotation" }}{{ $c.Name }}: {{ $cann.Attr "graphql_type" }}{{- with $cann.Attr "deprecated" }} @deprecated(reason: "{{ . }}"){{ end }}{{- end }}{{- end }}}{{- end }}
Run atlas schema inspect --env local --export and the per-table template produces:
"""A registered user"""type User {id: ID!name: String!nickname: String @deprecated(reason: "Use name instead")}
For full worked examples covering Hasura metadata, complete GraphQL schemas, and OpenAPI 3.0 specs, see the Template Exporter guide.