Front-End Web & Mobile
New: Announcing custom primary key support for AWS Amplify DataStore
Amplify DataStore provides frontend app developers the ability to build real-time apps with offline capabilities by storing data on-device (web browser or mobile device) and automatically synchronizing data to the cloud and across devices on an internet connection. Since its initial release, DataStore has been opinionated with regards to the handling of model identifiers – all models have by default an id
field that is automatically populated on the client with a UUID v4. This opinionated stance has allowed DataStore to generate non-colliding (with a very small probability) globally unique identifiers in a scalable way. However, UUIDs are large, non-sequential, and opaque.
Today, we are introducing the release of custom primary keys, also known as custom identifiers, for Amplify DataStore to provide additional flexibility for your data models. For instance to:
- Have friendly/readable identifiers (surrogate/opaque vs natural keys)
- Define composite primary keys
- Customize your data partitioning to optimize for scale
- 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 Amplify DataStore
What we’ll learn:
- How to configure and deploy an AppSync API and GraphQL schema using Amplify CLI to use a custom primary key as the unique identifier for a given model, including the ability to define composite primary keys – keys that requires multiple fields
- How you can create, read, update, and delete data using Amplify DataStore when working with custom primary keys
What we’ll build:
- A React-based Movie Collection app with public read and write permissions
- Users can delete records using custom primary and composite keys

Figure 1 – GIF showing records queried by Custom Primary Key
Prerequisites
- Install and configure the latest version of the Amplify CLI
Setup a new React Project
Run the following command to create a new Amplify project through Create-React-App called amplify-movies.
Setup your app backend with Amplify CLI
Run the following command to initialize an Amplify project with default values
Once complete, your project is initialized and connected to the cloud backend. Let’s add a API category to your app using:
and choose from the following options:
Enable Conflict Detection and select a Resolution Strategy
Create Movie Schema with custom primary key
Edit the schema at amplify/backend/api/amplifymovies/schema.graphql
You have a created a Movie model with a custom primary key of imdb using the @primaryKey directive. You have other fields for title, status, rating and description. Let us also define an enum called MovieStatus to hold the values for UPCOMING and RELEASED movies.
Note – Since we are using public as the authorization mode, we are adding the @auth directive to our Movie type, which uses an API Key to authorize graphql queries and mutations from our app. You can configure additional authorization rules as per your schema requirements here
Now that you have your schema setup, let’s deploy your app backend to create your GraphQL API. Run the following command:
Your app with Movie schema has been deployed successfully. Now let’s focus on client-side code.
Install and Initialize Amplify Libraries
Run the following command to install Amplify libraries and UI components:
To learn more about Amplify UI React components, visit Amplify UI Docs
In your index.js (src/index.js
), initialize Amplify library by adding the following:
Setup your frontend UI code
The UI code consists of –
- Form – A simple form to add movies into the DB
- Search – Ability to search movies by custom primary key
- Movie Card – Display collection of Movies through Card components
Let’s create a Movie Card component to display the movies added into your collection. Create a new folder under src/components
We will import Amplify UI components. For a visual description of the movie, let’s use movie posters. This is available via the omdbapi. Let’s pass the title info to the API which will return the corresponding poster of the movie.
For further information on the API, please visit OMDB API. Once you have your own API KEY, create a .env file in the root directory of your project and set it as the value of the environment variable REACT_APP_OMDB_API_KEY. You must restart your dev server after making changes to the .env file in order for the environment variables to be reflected in your application.
Create a new file called MovieCard.js
and add the following code:
Now, let’s build our App.js
file. Replace the content of your App.js file with the following:
Test your app on your local machine by running:
This serves an app where you can add Movies using a Custom Primary Key which, for the purpose of demonstration, we’ll name imdb. You will also be able to see the movies you add and search for a specific movie using the Custom Primary Key.
Creating Records with Custom Primary Key

Figure 2 – GIF showing creating records with Custom Primary Key
When creating a record with a custom primary key, we can specify the value for the primary key imdb instead of DataStore auto-generating a unique id for each new record.
Querying Records by Custom Primary Key

Figure 3 – GIF showing query by custom primary key
This query will behave the same as having an auto-generated id field in our schema, except now each record’s imdb number is treated as the unique identifier of the record and DataStore will use it to retrieve and return a single matching record.
Deleting Records by Custom Primary Key
Deleting records with a custom primary key behaves the same as deleting a record with an auto-generated id.
Update Schema with a Composite Key
Now that we have experience with using Custom Primary Key and building your favorite Movie collection app, let’s add a model with a composite key to your schema.
Edit your amplify/backend/api/amplifymovies/schema.graphql
to make the below changes:
Note – We are creating a new Model because you cannot update a Primary Key once created and deployed. This will result in an error when you run amplify push.
For the purposes of demonstrating the differences in accessing data with composite keys with DataStore, we are defining a new Model called MovieComposite, with a composite key made up of a record’s imdb, title and status fields.
Run the following command to deploy your schema changes to the backend:
Now, let’s build our App.js file. Replace the content of your App.js file with the following:
Test your app on your local machine by running:
Creating a record is the same between a model with a custom primary key and a model with a composite key. So, we’re going to focus on the differences when querying.
Querying for a single record by Composite Key

Figure 4 – GIF showing querying a single record by Composite Key
In our code that demonstrated using a custom primary key, we had to create Movie records with unique imdb numbers and were able to query those records specifically as such. With a composite key we are able to create records with the same primary key value. While we can still query by primary key, we cannot reliably retrieve a particular record if more than one record share the same primary key value. For example, given this dataset:

Figure 5 – Image showing a sample dataset for movies
Say we want to retrieve the record with a title of “The Dark Knight”. If we use the same syntax we did when our schema only had a custom primary key and no sort keys, DataStore will throw an error. Instead, we must use a composite key to ensure that we are being specific enough about the record we want. So, in addition to the imdb number, we must also specify both the title and status. This can be done either using an object literal or predicate syntax.
Query
OR

Figure 6 – Image showing the result of DataStore query in a table
Querying for multiple records by Primary Key

Figure 7 – GIF showing query of multiple records by Custom Primary Key
With a model that uses a composite key, we can create multiple records with the same primary key value. Let’s say we wanted to query for all records that share the same imdb number. In order to do so, we must use a predicate so that DataStore returns an array of all matching records rather than the first inserted.
Given the same dataset, we can retrieve all records with an imdb number of 1 like so:
Query
Result

Figure 8 – Image showing results of query for multiple records by Custom Primary Key
Deleting records by Composite Key
The behavior for deleting records is a bit different between a model with a primary key and one with a composite key. In our app code, we are deleting a single record by passing in a given record’s imdb, title, and status fields which, together, make up the composite key and uniquely identify the record we want to delete.
When a model uses composite keys, we’re able to delete all records with the same imdb number, or primary key, by using a predicate.
Conclusion
In this post, we have a full-fledged Movie Collection App making use of both Custom Primary Keys and Composite Keys. If you would like to learn more about Advanced Workflows with Amplify DataStore, please visit:
Clean Up
Now that you have successfully deployed the app and tested the new features of Amplify DataStore using Custom Primary Keys, you can run the following command to delete the backend resources to avoid incurring costs:
About the authors: