Schemas and keys

How to define schemas and keys

If you’re looking for an introduction to streams in Beneath, head over to the Concepts section.


Every stream in Beneath has a schema and a key:

  • The schema defines fields and data types for records in the stream. It is a variant of the GraphQL schema definition language.
  • The key defines one or more fields that uniquely identify the record (also known as a primary key or unique key). It is used for log compaction and table indexing.

Here is an example:

type Click @schema {
  user_id: Int! @key
  time: Timestamp! @key
  label: String!
  details: String

Beneath enforces some special conventions on top of the normal GraphQL language:

  • Field names must be specified in snake_case and type names in PascalCase
  • The schema type should have an @schema annotation
  • The @key annotation specifies the key field(s), where multiple @key annotations create a composite key in the respective order
  • Key fields must be marked required with an exclamation mark (e.g. foo: Int!)

Primitive types

The supported primitive types are:

Type Definition
Boolean True or false
Int or Int64 A 64-bit whole number
Int32 A 32-bit whole number
Float or Float64 A 64-bit (double precision) IEEE 754 floating-point number
Float32 A 32-bit (single precision) IEEE 754 floating-point number
String A variable-length sequence of unicode characters
Bytes A variable-length sequence of bytes
BytesN A fixed-length sequence of N bytes, e.g. Bytes32
Numeric An arbitrarily large whole number
Timestamp A millisecond-precision UTC date and time

Nested types

You can define nested types (the @schema annotation indicates the main type):

type Place @schema {
  place_id: Int! @key
  location: Point!
  label: String

type Point {
  x: Float!
  y: Float!

However, we generally encourage flat schemas as they are easier to analyze with SQL and look nicer in tables (e.g., in the example, location could be flattened to location_x and location_y).


You can define enums, for example:

type Journey @schema {
  journey_id: String! @key
  kind: Vehicle!
  distance_km: Int

enum Vehicle {