AWS AppSync Integration in Mobile Applications
AWS AppSync is managed GraphQL service from Amazon. It takes responsibility for hosting GraphQL API, connecting to data sources (DynamoDB, Lambda, RDS, Elasticsearch), WebSocket connections for subscriptions, and offline sync via conflict resolution. For mobile apps this means: single entry point instead of multiple REST endpoints, real-time out of the box, and built-in offline work via Amplify DataStore.
Architecture: AppSync + Amplify vs Raw Amplify SDK
AppSync operates on top of GraphQL. Amplify is AWS SDK for mobile platforms including AppSync client. Important to understand difference:
- Amplify API (GraphQL) — thin wrapper over AppSync, sends requests directly, no local cache
- Amplify DataStore — full offline-first layer: syncs data between local DB (SQLite) and AppSync, resolves conflicts
For most mobile apps DataStore is correct choice: app works without internet, syncs on network appear. For simple request-response without offline — Amplify API is simpler.
Configuration: amplify.json and Codegen
AppSync schema defined in schema.graphql. Amplify CLI generates client code:
amplify init
amplify add api # select GraphQL, AppSync
amplify codegen add --generate-code-settings
amplify push
After amplify push project gets:
-
amplifyconfiguration.json— endpoint, region, auth mode config - Generated models (
ModelPost.swift/ModelPost.kt) - Generated queries/mutations/subscriptions
Codegen is one of main AppSync wins: no need to manually write GraphQL queries and mapping.
Android: Amplify SDK
// build.gradle
implementation 'com.amplifyframework:aws-api:2.x.x'
implementation 'com.amplifyframework:aws-datastore:2.x.x'
// Application.onCreate()
try {
Amplify.addPlugin(AWSApiPlugin())
Amplify.addPlugin(AWSDataStorePlugin())
Amplify.configure(applicationContext)
} catch (e: AmplifyException) {
Log.e("App", "Init failed", e)
}
DataStore operations:
// Creation
val post = Post.builder()
.title("Hello")
.content("World")
.build()
Amplify.DataStore.save(post,
{ Log.i("DataStore", "Saved") },
{ Log.e("DataStore", "Error", it) }
)
// Subscribe to changes (real-time)
Amplify.DataStore.observe(Post::class.java,
{ Log.i("DataStore", "Observation started") },
{ change ->
val updatedPost = change.item()
},
{ Log.e("DataStore", "Error", it) },
{ Log.i("DataStore", "Complete") }
)
Coroutines extensions: amplify-kotlin package provides Amplify.DataStore.save(post) as suspend function — much cleaner than callback hell.
iOS: Amplify Swift
// Package.swift or Podfile
.package(url: "https://github.com/aws-amplify/amplify-swift", from: "2.x.x")
// AppDelegate / App init
try Amplify.add(plugin: AWSAPIPlugin())
try Amplify.add(plugin: AWSDataStorePlugin(modelRegistration: AmplifyModels()))
try Amplify.configure()
// DataStore with async/await
func savePost() async throws {
let post = Post(title: "Hello", content: "World")
try await Amplify.DataStore.save(post)
}
// Subscribe via AsyncSequence
func observePosts() async {
let subscription = Amplify.DataStore.observe(Post.self)
do {
for try await change in subscription {
print("Changed: \(change.element.title)")
}
} catch {
print("Observation failed: \(error)")
}
}
Authentication: Multiple Modes
AppSync supports multiple auth modes simultaneously:
| Mode | When to Use |
|---|---|
| API Key | Public content, prototypes |
| Amazon Cognito User Pools | Authorized users |
| AWS IAM | Machine-to-machine, AWS Lambda |
| OpenID Connect | External identity provider (Auth0, Okta) |
Typical config: public data via API Key, private via Cognito. AppSync resolvers use @auth directive in schema:
type Post @model @auth(rules: [
{ allow: public, provider: apiKey, operations: [read] },
{ allow: owner, operations: [create, update, delete] }
]) {
id: ID!
title: String!
content: String!
owner: String
}
@auth(allow: owner) automatically adds owner filter — user sees only own data.
Conflict Resolution in DataStore
When two devices offline edit same record, sync causes conflict. DataStore supports several strategies:
-
Auto Merge (default for
@modelwithout versioning) — last write wins -
Optimistic Concurrency — versioning via
_versionfield, on conflict AppSync calls Lambda to resolve - Custom Lambda Resolver — full control over logic
For most tasks Auto Merge sufficient. For financial data or chats — Custom Lambda with audit log.
Typical Integration Problems
Schema drift. Changing schema in AppSync Console without regenerating client models causes desynchronization. All schema changes — only via amplify push, never manually via console in production.
DataStore not syncing. Often cause — wrong @auth in schema: DataStore can't sync without list operation rights.
Subscriptions break. AppSync WebSocket connection breaks after 2 minutes inactivity by default. Amplify client auto-reconnects, but subscriptions must be recreated via Amplify.DataStore.observe — they don't auto-restore.
What's Included in Work
Design GraphQL schema with @model, @auth, and relationships, setup AppSync via Amplify CLI or CDK, integrate Amplify SDK on Android/iOS with needed auth mode, setup DataStore or API depending on offline requirements, test conflict resolution.
Timeline: 2–4 weeks depending on data schema complexity and offline requirements.







