Name:
interface
Value:
Amplify has re-imagined the way frontend developers build fullstack applications. Develop and deploy without the hassle.

Page updated Apr 29, 2024

LegacyYou are viewing Gen 1 documentation. Switch to the latest Gen 2 docs →

Customize primary keys

Customize primary keys

By default, DataStore models have an id field that is automatically populated on the client with a UUID v4, allowing DataStore to generate non-colliding globally unique identifiers in a scalable way. While UUIDs have desirable properties (they are large, non-sequential and opaque), there are times when a custom primary key, also known as custom identifier, is needed. For instance, to:

  • Have friendly/readable identifiers (surrogate/opaque vs. natural keys)
  • Define composite primary keys
  • Customize data partitioning to optimize for scale (especially important when planning to handle large amounts of data in short periods of time)
  • Selectively synchronize data to clients (e.g. by fields like deviceId, userId or similar)
  • Prioritize the sort order in which objects are returned by the sync queries
  • Make existing data consumable and syncable by DataStore

A schema with the typical id field looks like this:

type Book @model {
id: ID!
title: String!
description: String
}

You can customize the primary key by adding the @primaryKey directive to a field:

type Book @model {
isbn: ID! @primaryKey
title: String!
description: String
}

You can also require multiple fields to define your primary key. When your primary key references multiple fields, it's called a composite key. In the example below, the primary key is defined by the isbn and title fields:

type Book @model {
isbn: ID! @primaryKey(sortKeyFields: ["title"])
title: String!
description: String
}

Determine when the primary key field is auto-populated upon record creation

When you create a record with DataStore, a UUID is automatically populated for the default id: ID! primary key field. When working with custom primary keys, DataStore will automatically populate the key fields in the following conditions:

DescriptionTypeAutopopulated with UUID

Without @primaryKey

type Customer @model {
firstName: String
lastName: String
}
✅ Yes

Without @primaryKey, explicit id field

type Customer @model {
id: ID!
firstName: String
lastName: String
}
✅ Yes

@primaryKey on a custom field

type Customer @model {
customerId: ID! @primaryKey
firstName: String
lastName: String
}
❌ No

Explicit @primaryKey on id field

type Customer @model {
id: ID! @primaryKey
dob: AWSDateTime!
firstName: String
lastName: String
}
✅ Yes

Explicit @primaryKey on id field with sort key

type Customer @model {
id: ID! @primaryKey(sortKeyFields: ["dob"])
dob: AWSDateTime!
firstName: String
lastName: String
}
✅ Yes

Explicit id field in sort key

type Customer @model {
country: String! @primaryKey(sortKeyFields: ["id"])
id: ID!
firstName: String
lastName: String
}
✅ Yes

@primaryKey with no id field

type Customer @model {
zip: String! @primaryKey(sortKeyFields: ["username"])
username: String!
firstName: String
lastName: String
}
❌ No

Querying records with custom primary keys

A record of a model with custom primary key can be queried with query predicate in the following ways:

final book = (
await Amplify.DataStore.query(
Book.classType,
where: Book.ISBN.eq('12345'),
),
)[0];

You should always query by model identifier if the model has a composite primary key.

If you know the value of each field of the composite primary key, you can create a instance of the model identifier by using codegen generated class to create a query predicate:

final book = (
await Amplify.DataStore.query(
Book.classType,
where: Book.MODEL_IDENTIFIER.eq(
// BookModelIdentifier is a codegen generated class
// that is exported from ModelProvider.dart
BookModelIdentifier(
isbn: '12345',
),
),
),
)[0];

If you have the reference of a model instance, you can use the getter modelIdentifier to get the identifier of this instance, and to create a query predicate with it.

final reQueriedBook = (
await Amplify.DataStore.query(
Book.classType,
where: Book.MODEL_IDENTIFIER.eq(
book.modelIdentifier,
),
),
)[0];