export const meta = {
  title: `Data modeling`,
  description: `Add authorization rules to your GraphQL schema to control access to your data.`,
};

<MigrationAlert url={"/cli-legacy/graphql-transformer/key"}/>

Amplify automatically creates Amazon DynamoDB database tables for GraphQL types annotated with the `@model` directive in your GraphQL schema. You can create relations between the data models via the `@hasOne`, `@hasMany`, `@belongsTo`, and `@manyToMany` directives.

## Setup database tables

The following GraphQL schema automatically creates a database table for "Todo". `@model` will also automatically add an `id` field as a primary key to the database table. *See [Configure a primary key](#configure-a-primary-key) to learn how to customize the primary key.*

```graphql
type Todo @model {
  content: String
}
```

The Amplify CLI generates the Todo database table upon `amplify push` and generates a GraphQL API to perform create, read, update, delete, and list operations for the Todo model.

In addition, `@model` also adds the helper fields `createdAt` and `updatedAt` to your type. The values for those fields are read-only by clients unless explicitly overwritten. See [Customize creation and update timestamps](#customize-creation-and-update-timestamps) to learn more.

Try listing all the todos by executing the following query:
```graphql
query QueryAllTodos {
  listTodos() {
    todos {
      items {
        id
        content
        createdAt
        updatedAt
      }
    }
  }
}
```
```js
import { Amplify, API, graphqlOperation } from 'aws-amplify';
import awsconfig from './aws-exports';
import { listTodos } from './graphql/queries';

Amplify.configure(awsconfig);

try {
	const result = await API.graphql(graphqlOperation(listTodos));
	const todos = result.data.listTodos;
} catch (res) {
	const { errors } = res;
	console.error(errors);
}
```

### Configure a primary key

Every GraphQL type with the `@model` directive will automatically have an `id` field set as the primary key. You can override this behavior by marking another required field with the `@primaryKey` directive.

In the example below, `todoId` is the database's primary key and an `id` field will no longer be created automatically anymore by the `@model` directive.
```graphql
type Todo @model {
  todoId: ID! @primaryKey
  content: String
}
```

Without any further configuration, you'll only be able to query for a Todo via an exact equality match of its primary key field. In the example above, this is the `todoId` field.

> Note: After a primary key is configured and deployed, you can't change it without deleting and recreating your database table.

You can also specify "sort keys" to use a combination of different fields as a primary key. This also allows you to apply more advanced sorting and filtering conditions on the specified "sort key fields".

```graphql
type Inventory @model {
  productID: ID! @primaryKey(sortKeyFields: ["warehouseID"])
  warehouseID: ID!
  InventoryAmount: Int!
}
```

The schema above will allow you to pass different conditions to query the correct inventory item:
```graphql
query QueryInventoryByProductAndWarehouse($productID: ID!, $warehouseID: ID!) {
  getInventory(productID: $productID, warehouseID: $warehouseID) {
    productID
    warehouseID
    inventoryAmount
  }
}
```
```js
import { getInventory } from './graphql/queries';

const params = {
	productID: 'product-id',
	warehouseID: 'warehouse-id',
};

const result = await API.graphql(graphqlOperation(getInventory, params));
const inventory = result.data.getInventory;
```

### Configure a secondary index

Amplify uses Amazon DynamoDB tables as the underlying data source for @model types. For key-value databases, it is critical to model your access patterns with "secondary indexes". Use the `@index` directive to configure a secondary index. 

> **Amazon DynamoDB** is a key-value and document database that delivers single-digit millisecond performance at any scale but making it work for your access patterns requires a bit of forethought. DynamoDB query operations may use at most two attributes to efficiently query data. The first query argument passed to a query (the hash key) must use strict equality and the second attribute (the sort key) may use gt, ge, lt, le, eq, beginsWith, and between. DynamoDB can effectively implement a wide variety of access patterns that are powerful enough for the majority of applications.

A secondary index consists of a "hash key" and, optionally, a "sort key". Use the "hash key" to perform strict equality and the "sort key" for greater than (gt), greater than or equal to (ge), less than (lt), less than or equal to (le), equals (eq), begins with, and between operations. 

```graphql
type Customer @model {
  id: ID!
  name: String!
  phoneNumber: String
  accountRepresentativeID: ID! @index
}
```

The example client query below allows you to query for "Customer" records based on their `accountRepresentativeID`:

```graphql
query QueryCustomersForAccountRepresentative($accountRepresentativeID: ID!) {
  customersByAccountRepresentativeID(accountRepresentativeID: $accountRepresentativeID) {
    customers {
      items {
        id
        name
        phoneNumber
      }
    }
  }
}
```
```js
import { customersByAccountRepresentativeID } from './graphql/queries';

const params = {
	accountRepresentativeID: 'account-rep-id',
};

const result = await API.graphql(
	graphqlOperation(customersByAccountRepresentativeID, params)
);
const customers = result.data.customersByAccountRepresentativeID;
```

You can also overwrite the `queryField` or `name` to customize the GraphQL query name, or secondary index name respectively:

```graphql
type Customer @model {
  id: ID!
  name: String!
  phoneNumber: String
  accountRepresentativeID: ID! @index(name: "byRepresentative", queryField: "customerByRepresentative")
}
```

```graphql
query QueryCustomersForAccountRepresentative($representativeId: ID!) {
  customerByRepresentative(accountRepresentativeID: $representativeId) {
    customers {
      items {
        id
        name
        phoneNumber
      }
    }
  }
}
```
```js
import { customerByRepresentative } from './graphql/queries';

const params = {
	accountRepresentativeID: 'account-rep-id',
};

const result = await API.graphql(
	graphqlOperation(customerByRepresentative, params)
);
const customer = result.data.customerByRepresentative;
```

To optionally configure sort keys, provide the additional fields in the `sortKeyFields` parameter:

```graphql
type Customer @model @auth(rules: [{ allow: public }]) {
  id: ID!
  name: String! @index(name: "byNameAndPhoneNumber", sortKeyFields: ["phoneNumber"], queryField: "customerByNameAndPhone")
  phoneNumber: String
  accountRepresentativeID: ID! @index
```

The example client query below allows you to query for "Customer" based on their `name` and filter based on `phoneNumber`:

```graphql
query MyQuery {
  customerByNameAndPhone(phoneNumber: { beginsWith: "+1" }, name: "Rene") {
    items {
      id
      name
      phoneNumber
    }
  }
}
```
```js
import { customerByNameAndPhone } from './graphql/queries';

const params = {
	phoneNumber: { beginsWith: '+1' },
	name: 'Rene',
};

const result = await API.graphql(
	graphqlOperation(customerByNameAndPhone, params)
);
const customer = result.data.customerByNameAndPhone;
```

## Setup relationships between models

Create "has one", "has many", "belongs to", and "many to many" relationships between `@model` types.

|Relationship|Description|
|------------|--------|
|`@hasOne`|Create a one-directional one-to-one relationship between two models. For example, a Project "has one" Team. This allows you to query the team from the project record.
|`@hasMany`|Create a one-directional one-to-many relationship between two models. For example, a Post has many comments. This allows you to query all the comments from the post record.
|`@belongsTo`|Use a "belongs to" relationship to make a "has one" or "has many" relationship bi-directional. For example, a Project has one Team and a Team belongs to a Project. This allows you to query the team from the project record and vice versa.
|`@manyToMany`|Configures a "join table" between two models to facilitate a many-to-many relationship. For example, a Blog has many Tags and a Tag has many Blogs.  

### Has One relationship

import gqlv2callout from "/src/fragments/cli/gqlv2callout.mdx";

<Fragments fragments={{all: gqlv2callout}} />

Create a one-directional one-to-one relationship between two models using the `@hasOne` directive.

In the example below, a Project has a Team.
```graphql
type Project @model {
  id: ID!
  name: String
  team: Team @hasOne
}

type Team @model {
  id: ID!
  name: String!
}
```

This generates queries and mutations that allow you to retrieve the related record from the source record:

```graphql
mutation CreateProject {
  createProject(input: {projectTeamId: "team-id", name: "Some Name"}) {
    team {
      name
      id
    }
    name
    id
  }
}
```
```js
import { createProject } from './graphql/mutations';

const params = {
	input: { projectTeamId: 'team-id', name: 'Some Name' },
};

const result = await API.graphql(graphqlOperation(createProject, params));
const project = result.data.createProject;
```

To customize the field to be used for storing the relationship information, set the `fields` array argument and matching it to a field on the type:

```graphql
type Project @model {
  id: ID!
  name: String
  teamID: ID
  team: Team @hasOne(fields: ["teamID"])
}

type Team @model {
  id: ID!
  name: String!
}
```

In this case, the Project type has a `teamID` field added as an identifier for the team. @hasOne can then get the connected Team object by querying the Team table with this `teamID`:

```graphql
mutation CreateProject {
  createProject(input: { name: "New Project", teamID: "a-team-id"}) {
    id
    name
    team {
      id
      name
    }
  }
}
```
```js
import { createProject } from './graphql/mutations';

const params = {
	input: { teamID: 'team-id', name: 'New Project' },
};

const result = await API.graphql(graphqlOperation(createProject, params));
const project = result.data.createProject;
```

A `@hasOne` relationship always uses a reference to the primary key of the related model, by default `id` unless overridden with the [`@primaryKey` directive](#configure-a-primary-key).

### Has Many relationship

<Fragments fragments={{all: gqlv2callout}} />

Create a one-directional one-to-many relationship between two models using the `@hasMany` directive.

```graphql
type Post @model {
  id: ID!
  title: String!
  comments: [Comment] @hasMany
}

type Comment @model {
  id: ID!
  content: String!
}
```

This generates queries and mutations that allow you to retrieve the related Comment records from the source Post record:

```graphql
mutation CreatePost {
  createPost(input: {title: "Hello World!!"}) {
    title
    id
    comments {
      items {
        id
        content
      }
    }
  }
}
```
```js
import { createPost } from './graphql/mutations';

const params = {
	input: { title: 'Hello World!!' },
};

const result = await API.graphql(graphqlOperation(createPost, params));
const post = result.data.createPost;
const comments = post.comments.items;
```

Under the hood, `@hasMany` configures a default secondary index on the related table to enable you to query the related model from the source model.

To customize the specific secondary index used for the "has many" relationship, create an `@index` directive on the field in the related table where you want to assign the secondary index. 

Next, provide the secondary index with a `name` attribute and a value. Optionally, you can configure a “sort key” on the secondary index by providing a `sortKeyFields` attribute and a designated field as its value.

On the `@hasMany` configuration, pass in the name value from your secondary index as the value for the `indexName` parameter. Then, pass in the respective `fields` that match the connected index.


```graphql
type Post @model {
  id: ID!
  title: String!
  comments: [Comment] @hasMany(indexName: "byPost", fields: ["id"])
}

type Comment @model {
  id: ID!
  postID: ID! @index(name: "byPost", sortKeyFields: ["content"])
  content: String!
}
```

In this case, the Comment type has a `postID` field added to store the reference of Post record. The `id` field referenced by `@hasMany` is the `id` on the `Post` type. `@hasMany` can then get the connected Comment object by querying the Comment table's secondary index "byPost" with this `postID`:

```graphql
mutation CreatePost {
  createPost(input: {title: "Hello world!"}) {
    comments {
      items {
        postID
        content
        id
      }
    }
    title
    id
  }
}
```
```js
import { createPost, createComment } from './graphql/mutations';
import { getPost } from './graphql/mutations';

// create post
const postParams = {
	input: { title: 'Hello World!!' },
};

const result = await API.graphql(graphqlOperation(createPost, postParams));
const post = result.data.createPost;

// create comment
const commentParams = {
	input: { content: 'Hi!', postID: post.id },
};

await API.graphql(graphqlOperation(createComment, commentParams));

// get post
const result = await API.graphql(graphqlOperation(getPost, { id: post.id }));
const postWithComments = result.data.createPost;
const postComments = postWithComments.comments.items; // access comments from post
```

### Belongs To relationship

Make a "has one" or "has many" relationship bi-directional with the `@belongsTo` directive.

<BlockSwitcher>

<Block name='Bi-directional "has one" relationship'>

```graphql
type Project @model {
  id: ID!
  name: String
  team: Team @hasOne
}

type Team @model {
  id: ID!
  name: String!
  project: Project @belongsTo
}
```

This generates queries and mutations that allow you to retrieve the related Comment records from the source Post record and vice versa:

```graphql
mutation CreateProject {
  createProject(input: { name: "New Project", teamID: "a-team-id"}) {
    id
    name
    team { # query team from project
      id
      name
      project { # bi-directional query: team to project
        id
        name
      }
    }
  }
}
```
```js
import { createProject, createTeam, updateTeam } from './graphql/mutations';

// create team
const teamParams = {
	input: { name: 'New Team' },
};

const result = await API.graphql(graphqlOperation(createTeam, teamParams));
const team = result.data.createTeam;

// create project
const projectParams = {
	input: { name: 'New Project', projectTeamId: team.id },
};

const result = await API.graphql(
	graphqlOperation(createProject, projectParams)
);
const project = result.data.createProject;
const projectTeam = project.team; // access team from project

// update team
const updateParams = {
	input: { id: team.id, teamProjectId: project.id },
};

const updateTeamResult = await API.graphql(
	graphqlOperation(updateTeam, updateParams)
);

const updatedTeam = updateTeamResult.data.updateTeam;
const teamProject = updatedTeam.project; // access project from team
```

</Block>

<Block name='Bi-directional "has many" relationship'>

```graphql
type Post @model {
  id: ID!
  title: String!
  comments: [Comment] @hasMany
}

type Comment @model {
  id: ID!
  content: String!
  post: Post @belongsTo
}
```

This generates queries and mutations that allow you to retrieve the related Comment records from the source Post record and vice versa:

```graphql
mutation CreatePost {
  createPost(input: {title: "Hello World!!"}) {
    title
    id
    comments { # query comments from the post
      items {
        id
        content
        post { # bi-directional query: comment to post
          id
          title
        }
      }
    }
  }
}
```
```js
import { createPost, createComment } from './graphql/mutations';
import { getPost } from './graphql/mutations';

// create post
const postParams = {
	input: { title: 'Hello World!!' },
};

const result = await API.graphql(graphqlOperation(createPost, postParams));
const post = result.data.createPost;

// create comment
const commentParams = {
	input: { content: 'Hi!', postID: post.id },
};

await API.graphql(graphqlOperation(createComment, commentParams));

// get post
const result = await API.graphql(graphqlOperation(getPost, { id: post.id }));
const postWithComments = result.data.createPost;
const postComments = postWithComments.comments.items; // access comments from post

const commentPost = postComments[0].post; // access post from comment;
```
</Block>

</BlockSwitcher>

`@belongsTo` can be used without the `fields` argument. In those cases, a field is automatically generated to reference the parent’s primary key.

Alternatively, you set up a custom field to store the reference of the parent object. An example bidirectional “has many” relationship is shown below.

```graphql
type Post @model {
  id: ID!
  title: String!
  comments: [Comment] @hasMany(indexName: "byPost", fields: ["id"])
}

type Comment @model {
  id: ID!
  postID: ID! @index(name: "byPost", sortKeyFields: ["content"])
  content: String!
  post: Post @belongsTo(fields: ["postID"])
}
```

> Note: The `@belongsTo` directive requires that a `@hasOne` or `@hasMany` relationship already exists from parent to the related model. 

### Many-to-many relationship
Create a many-to-many relationship between two models with the `@manyToMany` directive. Provide a common `relationName` on both models to join them into a many-to-many relationship. 

```graphql
type Post @model {
  id: ID!
  title: String!
  content: String
  tags: [Tag] @manyToMany(relationName: "PostTags")
}

type Tag @model {
  id: ID!
  label: String!
  posts: [Post] @manyToMany(relationName: "PostTags")
}
```

Under the hood, the `@manyToMany` directive will create a "join table" named after the `relationName` to facilitate the many-to-many relationship. This generates queries and mutations that allow you to retrieve the related Comment records from the source Post record and vice versa:

```graphql
mutation CreatePost {
  createPost(input: {title: "Hello World!!"}) {
    id
    title
    content
    tags { # queries the "join table" PostTags
      items {
        tag { # related Tag records from Post
          id
          label
          posts { # queries the "join table" PostTags
            items {
              post { # related Post records from Tag
                id
                title
                content
              }
            }
          }
        }
      }
    }
  }
}
```
```js
import { createPost, createTag, createPostTags } from './graphql/mutations';
import { listPosts } from './graphql/queries';

// create post
const postParams = {
	input: { title: 'Hello World' },
};

const result = await API.graphql(graphqlOperation(createPost, postParams));
const post = result.data.createPost;

// create tag
const tagParams = {
	input: {
		label: 'My Tag',
	},
};

const tagResult = await API.graphql(graphqlOperation(createTag, tagParams));
const tag = tagResult.data.createTag;

// connect post and tag
const postTagParams = {
	input: {
		postId: post.id,
		tagId: tag.id,
	},
};

await API.graphql(graphqlOperation(createPostTags, postTagParams));

// get posts
const listPostsResult = await API.graphql(graphqlOperation(listPosts));
const posts = listPostsResult.data.listPosts;

const postTags = posts[0].tags; // access tags from post
```

## Assign default values for fields

You can use the `@default` directive to specify a default value for optional [scalar type fields](https://docs.aws.amazon.com/appsync/latest/devguide/scalars.html) such as `Int`, `String`, and more. 

```graphql
type Todo @model {
  content: String @default(value: "My new Todo")
}
```

If you create a new Todo and don't supply a `content` input, Amplify will ensure that `My new Todo` is auto populated as a value. 
When `@default` is applied, non-null assertions using `!` are disregarded. For example, `String!` is treated the same as `String`.

## Server-side filtering for subscriptions

A server-side subscription filter expression is automatically generated for any `@model` type.

```graphql
type Task @model {
  title: String!
  description: String
  type: String
  priority: Int
}
```

You can filter the subscriptions server-side by passing a filter expression. For example: If you want to subscribe to tasks of type `Security` and priority greater than `5`, you can set the `filter` argument accordingly.

```graphql
subscription OnCreateTask {
  onCreateTask(
    filter: {
      and: [
        { type: { eq: "Security" } }
        { priority: { gt: 5 } }
      ]
    }
  ) {
    title
    description
    type
    priority
  }
}
```
```js
import { onCreateTask } from './graphql/subscriptions';

const filter = {
	and: [
		{ type: { eq: "Security" } }
		{ priority: { gt: 5 } }
  ]
};

const subscription = API.graphql(graphqlOperation(onCreateTask, filter)).subscribe({
	next: ({ provider, value }) => console.log({ provider, value }),
	error: (error) => console.warn(error)
});
```

If you want to get all subscription events, don’t pass any `filter` parameters.

<Callout>

**Important**: Passing an empty object `{}` as a filter is NOT recommended. Using `{}` as a filter might cause inconsistent behavior based on your data model's authorization rules.

</Callout>

## Advanced

### Rename generated queries, mutations, and subscriptions

You can override the names of any `@model`-generated GraphQL queries, mutations, and subscriptions by supplying the desired name.

```graphql
type Todo @model(queries: { get: "queryFor" }) {
  name: String!
  description: String
}
```

In the example above, you will be able to run a `queryForTodo` query to get a single Todo element.  

### Disable generated queries, mutations, and subscriptions

You can disable specific operations by assigning their value to `null`.

```graphql
type Todo @model(queries: { get: null }, mutations: null, subscriptions: null) {
  name: String!
  description: String
}
```

The example above disables the `getTodo` query, all mutations, and all subscriptions while allowing the generation of other queries such as `listTodo`.

### Creating a custom query

You can disable the `get` query and create a custom query that enables us to retrieve a single Todo model.

```graphql
type Query {
   getMyTodo(id: ID!): Todo @function(name: "getmytodofunction-${env}")
}
```

The example above creates a custom query that utilizes the `@function` directive to call a Lambda function for this query.

For the type definitions of queries, mutations, and subscriptions, see [Type Definitions of the `@model` Directive](#type-definition-of-the-`@model`-directive).

### Customize creation and update timestamps
The `@model` directive automatically adds `createdAt` and `updatedAt` timestamps to each entity. The timestamp field names can be changed by passing timestamps attribute to the directive.

```graphql
type Todo @model(timestamps: { createdAt: "createdOn", updatedAt: "updatedOn" }) {
  name: String!
  description: String
}
```

For example, the schema above will allow you to query for the following contents:

```graphql
type Todo {
  id: ID!
  name: String!
  description: String
  createdOn: AWSDateTime!
  updatedOn: AWSDateTime!
}
```

### Modify subscriptions (real-time updates) access level

By default, real-time updates are on for all `@model` types, which means customers receive real-time updates and authorization rules are applied during initial connection time. You can also turn off subscriptions for that model or make the real-time updates public, receivable by all subscribers.

```graphql
type Todo @model(subscriptions: { level: off }) { # or level: public
  name: String!
  description: String
}
```

### Create multiple relationships between two models

You need to explicitly specify the connection field names if relational directives are used to create two connections of the same type between the two models.

```graphql
type Individual @model {
  id: ID!
  homeAddress: Address @hasOne
  shippingAddress: Address @hasOne
}

type Address @model {
  id: ID!
  homeIndividualID: ID
  shippingIndividualID: ID
  homeIndividual: Individual @belongsTo(fields: ["homeIndividualID"])
  shipIndividual: Individual @belongsTo(fields: ["shippingIndividualID"])
}
```

### Relationships to a model with a composite primary key

When a primary key is defined by a *sort key* in addition to the *hash key*, then it's called a **composite primary key**.

If you explicitly define the `fields` argument on the `@hasOne`, `@hasMany`, or `@belongsTo` directives and reference a model that has a composite primary key, then you must set the values in the `fields` argument in a specific order:

- The first value should always be the primary key of the related model.
- Remaining values should match the `sortKeyFields` specified in the `@primaryKey` directive of the related model.

<BlockSwitcher>

<Block name='Uni-directional "has one"'>

```graphql
type Project @model {
  projectId: ID! @primaryKey(sortKeyFields:["name"])
  name: String!
  team: Team @hasOne(fields:["teamId", "teamName"])
  teamId: ID # customized foreign key for child primary key
  teamName: String # customized foreign key for child sort key
}

type Team @model {
  teamId: ID! @primaryKey(sortKeyFields:["name"])
  name: String!
}
```

</Block>

<Block name='Bi-directional "has one"'>

```graphql
type Project @model {
  projectId: ID! @primaryKey(sortKeyFields:["name"])
  name: String!
  team: Team @hasOne(fields:["teamId", "teamName"])
  teamId: ID # customized foreign key for child primary key
  teamName: String # customized foreign key for child sort key
}

type Team @model {
  teamId: ID! @primaryKey(sortKeyFields:["name"])
  name: String!
  project: Project @belongsTo(fields:["projectId", "projectName"])
  projectId: ID # customized foreign key for parent primary key
  projectName: String # customized foreign key for parent sort key
}
```

</Block>

<Block name='Uni-directional "has many"'>

```graphql
type Post @model {
  postId: ID! @primaryKey(sortKeyFields:["title"])
  title: String!
  comments: [Comment] @hasMany(indexName:"byPost", fields:["postId", "title"])
}

type Comment @model {
  commentId: ID! @primaryKey(sortKeyFields:["content"])
  content: String!
  postId: ID @index(name: "byPost", sortKeyFields:["postTitle"]) # customized foreign key for parent primary key
  postTitle: String # customized foreign key for parent sort key
}
```

</Block>

<Block name='Bi-directional "has many"'>

```graphql
type Post @model {
  postId: ID! @primaryKey(sortKeyFields:["title"])
  title: String!
  comments: [Comment] @hasMany(indexName:"byPost", fields:["postId", "title"])
}

type Comment @model {
  commentId: ID! @primaryKey(sortKeyFields:["content"])
  content: String!
  post: Post @belongsTo(fields:["postId", "postTitle"])
  postId: ID @index(name: "byPost", sortKeyFields:["postTitle"]) # customized foreign key for parent primary key
  postTitle: String # customized foreign key for parent sort key
}
```

</Block>



</BlockSwitcher>

### Generate a secondary index without a GraphQL query

Because query creation against a secondary index is automatic, if you wish to define a secondary index that does not have a corresponding query in your API, set the `queryField` parameter to `null`.

```graphql
type Customer @model {
  id: ID!
  name: String!
  phoneNumber: String
  accountRepresentativeID: ID! @index(queryField: null)
}
```

## How it works
### Model directive
The `@model` directive will generate:
- An Amazon DynamoDB table with PAY_PER_REQUEST billing mode enabled by default.
- An AWS AppSync DataSource configured to access the table above.
- An AWS IAM role attached to the DataSource that allows AWS AppSync to call the above table on your behalf.
- Up to 8 resolvers (create, update, delete, get, list, onCreate, onUpdate, onDelete) but this is configurable via the queries, mutations, and subscriptions arguments on the @model directive.
- Input objects for create, update, and delete mutations.
- Filter input objects that allow you to filter objects in list queries and relationship fields.
- For list queries the default number of objects returned is 100. You can override this behavior by setting the limit argument.

**Type definition of the `@model` directive**
```graphql
directive @model(
  queries: ModelQueryMap
  mutations: ModelMutationMap
  subscriptions: ModelSubscriptionMap
  timestamps: TimestampConfiguration
) on OBJECT

input ModelMutationMap {
  create: String
  update: String
  delete: String
}

input ModelQueryMap {
  get: String
  list: String
}

input ModelSubscriptionMap {
  onCreate: [String]
  onUpdate: [String]
  onDelete: [String]
  level: ModelSubscriptionLevel
}

enum ModelSubscriptionLevel {
  off
  public
  on
}

input TimestampConfiguration {
  createdAt: String
  updatedAt: String
}
```

### Relational directives
The relational directives are `@hasOne`, `@hasMany`, `@belongsTo` and `@manyToMany`.
<BlockSwitcher>
<Block name="@hasOne">

The `@hasOne` will generate:

- Foreign key fields in parent type that refer to the primary key and sort key fields of the child model.
- Foreign key fields in parent input object of `create` and `update` mutations.

**Type definition of the `@hasOne` directive**

```graphql
directive @hasOne(fields: [String!]) on FIELD_DEFINITION
```
</Block>
<Block name="@hasMany">

The `@hasMany` will generate:

- Foreign key fields in child type that refer to the primary key and sort key fields of the parent model.
- Foreign key fields in child input object of `create` and `update` mutations.
- A global secondary index (GSI) in the child type Amazon DynamoDB table.

**Type definition of the `@hasMany` directive**

```graphql
directive @hasMany(indexName: String, fields: [String!], limit: Int = 100) on FIELD_DEFINITION
```

- The default number of nested objects returned is 100. You can override this behavior by setting the limit argument.

</Block>
<Block name="@belongsTo">

The `@belongsTo` will generate:

- Foreign key fields that refer to the primary key and sort key fields of the related model.
- Foreign key fields in the input object of `create` and `update` mutations.

**Type definition of the `@belongsTo` directive**

```graphql
directive @belongsTo(fields: [String!]) on FIELD_DEFINITION
```
</Block>
<Block name="@manyToMany">

The `@manyToMany` will generate:

- A joint table defining the intermediate model type with the name of `relationName`.
- Foreign key fields in the joint table that refer to the primary key and sort key fields of both models.
- Foreign key fields in the intermediate model input object of `create` and `update` mutations.

**Type definition of the `@manyToMany` directive**

```graphql
directive @manyToMany(relationName: String!, limit: Int = 100) on FIELD_DEFINITION
```
- The default number of nested objects returned is 100. You can override this behavior by setting the limit argument.

</Block>
</BlockSwitcher>