Build fast React Native apps with AWS Amplify



In this article, we will be building a mobile application with React Native using Expo SQLite adapter as a storage adapter for DataStore.

By the end of the of article, you will be able to build a contact app using the SQLite adapter for storage as shown in the video below:

Expo enables developers to create hybrid JavaScript applications from the comfort of their terminals. Expo has an adapter that gives your app access to a database that can be queried through a WebSQL-like API called expo-sqlite. The database is persisted across restarts of your app.

Datastore allows you to interact with your data offline first, and it has a sync engine behind the scenes to send data to the backend. DataStore provides a model for using distributed or shared data without writing any additional code for implementing online and offline states. This programming model ensures that working with distributed or shared data is as easy as working with local data. DataStore provides data modeling using GraphQL and converts it to models that you can use in building JavaScript, Android, iOS, and Flutter applications.

With DataStore, at runtime models are passed into a Storage Engine that has a Storage Adapter. Amplify ships with default Storage Adapter implementations, such as SQLite and IndexedDB.


  • Nodejs ≥v14 installed
  • Knowledge of JavaScript and React
  • AWS Amplify CLI installed
npm install -g @aws-amplify/cli
  • AWS Amplify configured
amplify configure
  • Expo CLI installed
npm install -g expo-cli
  • Expo Go (installed from your mobile playstore)

Building the React Native app with Expo SQLite and Datastore

Let’s get started by initializing a new Expo app. Run this command on your terminal

expo init ReactAmplifyDataStoreExpo

This will create a new React Native application. Change directory and initialize amplify on the directory with these commands

cd AmplifyDataStoreExpo
npx amplify-app@latest

Installing Dependencies

Next, install the following dependencies with expo

expo install aws-amplify @aws-amplify/datastore-storage-adapter expo-sqlite expo-file-system @react-native-community/netinfo @react-native-async-storage/async-storage
  • aws-amplify: this package will enable us to build our AWS cloud-enabled mobile application.
  • @aws-amplify/datastore-storage-adapter: this is the SQLite storage adapter for Amplify Datastore
  • expo-sqlite: this package gives the app access to a database that can be queried through a WebSQL-like API.
  • expo-file-system: This package provides access to the local file system on the device.
  • @react-native-community/netinfo: this package is the React Native Network Info API for Android, iOS, macOS, Windows & Web. It allows you to get information on Connection type and Connection quality
  • @react-native-async-storage/async-storage: This is an asynchronous, unencrypted, persistent, key-value storage system for React Native.

Next, we go on to create the model for our application.

Generating model with Amplify

The first step to building an app backed by datastore is by defining a schema. The schema contains data types and relationships that represent the app’s functionality. In our app, we will create a schema for a simple contact application.
Head over to amplify/backend/api/schema.graphql, delete the content, and add these lines of code.

type Contact @model {
  id: ID!
  name: String!
  phone: String!
  email: String

Here, our Contact model has id, name, phone, and email as properties. Let’s now go ahead to create the graphql generated schema and models. Run this command on your terminal

npm run amplify-modelgen

This will create an src/models folder with the model and graphql schema. We are making progress!

Next, we initialize the amplify backend. Run this command on your terminal:

amplify init
? Enter a name for the environment dev
? Choose your default editor: Visual Studio Code
Using default provider  awscloudformation
? Select the authentication method you want to use: AWS profile

This will also create an aws-exports.js in the src directory. Awesome.
Next, we go ahead to deploy the amplify backend to the cloud. Run this command to do that:

amplify push

For this option, ? Do you want to generate code for your newly created GraphQL API No, choose No. We are choosing no here because we’ll be using the datastore API. This will take some time to deploy, depending on your network speed.

Importing Dependencies

Navigate to App.js, delete the content and add these lines of code:

import { DataStore } from 'aws-amplify';
import { ExpoSQLiteAdapter } from '@aws-amplify/datastore-storage-adapter/ExpoSQLiteAdapter';
import Amplify from '@aws-amplify/core';
import config from './src/aws-exports'
import React, { useState, useEffect } from 'react'
import { Text, View, TextInput, Button } from 'react-native'
import { Contact } from './src/models'

Here, we imported DataStore from amplify, we also got the ExpoSQLiteAdapter from amplify datastore storage adapter package and the Contact model from models.

Configuring Amplify and DataStore with ExpoSQLiteAdapter

Next, add these lines of code to App.js:


  storageAdapter: ExpoSQLiteAdapter

Here, we configure Amplify with config from aws-exports, and then we set ExpoSQLiteAdapter as the storageAdapter for Datastore. Let’s move on.

Implementing UI Inputs

  const initialState = { name: '', email: '', phone: '' }

  function App() {
      <View style={container}>
        <Text style={heading}> My Contacts </Text>
          onChangeText={v => onChangeText('name', v)}
          placeholder='Contact name'
          onChangeText={v => onChangeText('email', v)}
          placeholder='Contact email'
          onChangeText={v => onChangeText('phone', v)}
          placeholder='Contact phone'
        <Button onPress={createContact} title='Create Contact' />

Here, we start by setting the initial state of the input fields. We also have TextInput fields and a Button that invokes the createContact function onPress. Let’s go ahead and create the createContact function.

Implementing Create Contact Functionality

Add these lines of code to App.js

const [formState, updateFormState] = useState(initialState)

async function createContact() {
    if (! && ! && ! return
    await Contact({ ...formState }))

Then, we have two state variables, the first formState will get the values of the input fields and updateFormState will update the state when the onChangeText event is triggered.
Next, we have a createContact function. First, we have a condition that validates if the name, email, and phone fields are empty, if they are, the function returns false, else, we go on to save the field values to Datastore.

Implementing View Contact Functionality

Add these lines of code to App.js

  const [contacts, updateContacts] = useState([])

  async function fetchContacts() {
    const contacts = await DataStore.query(Contact)

The other variable is an array that holds the contacts we will be fetching from DataStore. Next, we have a fetchContacts function that queries the Contact model and then we update the contacts array.

  { => (
      <View key={}>
        <View style={contactBg}>
          <Text style={contactText}>Name: {}</Text>
          <Text style={contactText}>Email: {}</Text>
          <Text style={contactText}>Phone: {}</Text>

Here, we mapped through the contacts array to render the contact name, email, and phone.

Implementing onChangeText functionality

Add these lines of code to App.js

function onChangeText(key, value) {
    updateFormState({ ...formState, [key]: value })

When the onChangeText event is triggered the formState is updated with the field values.

Implementing Subscriptions with DataStore

Add these lines of code to App.js

useEffect(() => {
  const subscription = DataStore.observe(Contact).subscribe(() => fetchContacts())
  return () => subscription.unsubscribe()

Finally, we have a useEffect() where we call the fetchContacts(), and then we do something interesting. We create a graphql subscription with Datastore. So if you’re updating the contacts on the web, or iOS app, or Android, you can see those updates in real-time. Awesome.

Adding some Styles

We should go ahead to add the styles. Add the lines of code to the bottom of the codebase in App.js

const container = { padding: 20, paddingTop: 80 }
const input = { marginBottom: 10, padding: 7, backgroundColor: '#ddd' }
const heading = { fontWeight: 'normal', fontSize: 40 }
const contactBg = { backgroundColor: 'white' }
const contactText = { margin: 0, padding: 9, fontSize: 20 }

export default App


Now let’s go ahead and run the app. Run this command on your terminal.

expo start

You should have something like this in the terminal

➜  ReactAmplifyDataStoreExpo git:(master) ✗ expo start

This command is being executed with the global Expo CLI.
To use the local CLI instead (recommended in SDK 46 and higher), run:
› npx expo start

Starting project at /Users/mac/Desktop/sammy/ReactAmplifyDataStoreExpo
Starting Metro Bundler
█ ▄▄▄▄▄ █▀▄█▀     █ ▄▄▄▄▄ █
█ █   █ █▄   ▄██▀▀█ █   █ █
█ █▄▄▄█ █ ▀█▀█▄▀ ██ █▄▄▄█ █
█▄▄▄▄▄▄▄█ ▀▄█ █▄▀ █▄▄▄▄▄▄▄█
█▄▄▀ █▀▄▄██ ▀▄ ▀██▀  ▄▀▄▄▀█
█ ▄▄▀▄▀▄▀▄▄▄█▄  ▀▄▄▀ ▀▀█▄▄█
█▄▄ ▄ █▄▄██▀██▄ █▀█ ▄█ ██▀█
█▄▀██▀█▄ █▄█ ▄▀██ ▄▄ ▀▀██▄█
█▄▄██▄▄▄▄  ▀▀██▄  ▄▄▄ █ ▄ █
█ ▄▄▄▄▄ █▄▄▀▀▄▄▄  █▄█  ▀▄ █
█ █   █ █▀▀ ▄█ ▀▀▄ ▄▄ █▀▄██
█ █▄▄▄█ █▀▄ ██ ▄█  █▄  ▄█▄█

› Metro waiting on exp://
› Scan the QR code above with Expo Go (Android) or the Camera app (iOS)

› Press a │ open Android
› Press i │ open iOS simulator
› Press w │ open web

› Press r │ reload app
› Press m │ toggle menu

› Press ? │ show all commands

Logs for your project will appear below. Press Ctrl+C to exit.
Started Metro Bundler

Now launch the Expo Go app on your mobile, and scan the QR code. You should have something like this:

Awesome, you can go ahead to install

npm i react-native-web react-dom

This will enable viewing the app on your web browser.


Amplify DataStore allows you to start persisting data locally to your device with DataStore, even without an AWS account. In this article, we learned about Expo SQLite and we went on to build a React native app with Expo SQLite adapter and AWS Amplify DataStore.

Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post

…It Works Fine Locally

Next Post

Building infrastructure for an open-source programmable zapier

Related Posts