WordPress + GraphQL: Building a Mobile App Backend in Two Weeks
Why GraphQL for a WordPress-backed mobile app?
The brief on AzanGuru was simple but unforgiving: ship one Quran learning platform with a web app and a mobile app that share content, lesson state, and user progress in real time. The platform serves children and adults globally. WordPress was the obvious answer for the content management side. The hard part was the API surface that both the website and the mobile app would consume.
REST works but it requires multiple round trips per screen. GraphQL collapses those into a single typed query. For a mobile app on a slow network, that difference is huge.
What does GraphQL give you that REST does not?
Four practical advantages on a project like AzanGuru:
- One request per screen. A learner dashboard needs the user profile, the current lesson, the next three lessons, and progress. In REST that is four calls. In GraphQL that is one.
- Exact fields. Mobile clients can ask for only the fields they need. A list view does not pull the full lesson body.
- Strong typing. The generated TypeScript types match the schema exactly. Refactors are caught at compile time.
- Excellent developer experience. GraphiQL lets new team members explore the schema without reading API documentation.
The stack on AzanGuru
- Backend. WordPress, ACF Pro for structured fields, WPGraphQL for the GraphQL layer, custom WPGraphQL extensions for app-specific fields.
- Auth. WordPress users plus JWT for app sessions.
- Web frontend. Next.js with Apollo Client. Server-side rendered for marketing pages, dynamic for the learner area.
- Mobile app. React Native with Apollo Client. Single codebase ships to App Store and Google Play.
- Hosting. Tuned VPS for WordPress (the stack from my VPS article). Vercel for Next.js. App Store Connect + Google Play Console for the mobile binaries.
How do you set up WPGraphQL?
Install the WPGraphQL plugin from the WordPress repository. It is free and well-maintained. Once active, your site exposes /graphql which serves the GraphQL endpoint.
Default queries cover the WordPress core: posts, pages, users, categories, tags, custom post types. The schema is generated from registered post types and taxonomies — no manual schema authoring required for those basics.
How do you extend WPGraphQL with custom fields?
AzanGuru's content model needed lessons with structured fields: difficulty, sequence number, audio URL, related vocabulary, and teacher notes. ACF Pro stores those. WPGraphQL for ACF (a sibling plugin) exposes ACF fields automatically as GraphQL types.
For computed fields that are not stored — for example, "is this lesson available to this user given their plan?" — register a custom resolver:
add_action( 'graphql_register_types', function () {
register_graphql_field( 'Lesson', 'isAvailable', [
'type' => 'Boolean',
'resolve' => function( $post ) {
$user_id = get_current_user_id();
return azanguru_can_access_lesson( $user_id, $post->ID );
},
] );
} );
That field is now queryable from the mobile app exactly like any built-in field.
How do you handle authentication?
For the AzanGuru mobile app, authentication is JWT-based. The user logs in via a GraphQL mutation that returns a JWT. The app stores the token in secure storage (Keychain on iOS, EncryptedSharedPreferences on Android) and attaches it as a Bearer header on every subsequent request.
WPGraphQL supports JWT authentication via the WPGraphQL JWT Authentication plugin. The token includes the WordPress user ID and an expiration. Refresh tokens are issued with a longer lifetime to avoid forcing the user to log in every week.
How do you keep the mobile app fast?
Three practical patterns on AzanGuru:
- Apollo cache. Configure Apollo's normalised cache so that querying the same lesson from two screens does not hit the network twice.
- Pagination. Lesson lists use cursor-based pagination. Apollo's
fetchMoreappends new pages to the cache without invalidating existing entries. - Offline support. Critical data (current lesson, next three lessons) is persisted to disk via
apollo3-cache-persist. The app opens to last-known state even with no network.
How does the mobile app talk to the same backend as the web app?
Identical schema, identical queries, different clients. The web app uses Apollo Client in Next.js. The mobile app uses Apollo Client in React Native. Both target the same /graphql endpoint. The only differences are platform-specific concerns: secure storage, push notifications, in-app purchase.
The benefit on AzanGuru was significant. When we needed to add the homework submission feature, the WordPress mutation was written once and consumed from both the web app and the mobile app the same week. No second API to maintain.
What about performance on the WordPress side?
GraphQL on WordPress can be slow if you do not pay attention to the N+1 problem. A naive resolver that fetches each lesson individually for a list of 20 lessons makes 20 separate database queries.
WPGraphQL ships with DataLoader-style batching for core types, but custom resolvers need it added explicitly. Use the WPGraphQL connection_resolver patterns or batch lookups via get_posts() with all IDs at once.
On AzanGuru the slowest queries went from 800ms to under 100ms when batching was applied correctly. The technique is the most important single thing to learn about WPGraphQL performance.
What does the launched product look like?
The AzanGuru iOS app is live as "AzanGuru: Quran Learning App" with a 4.6★ rating across 16 App Store reviews. The Android app has crossed 100,000+ installs on Google Play. Both are powered by the same WordPress + WPGraphQL backend. The release cadence runs every 2-3 weeks because the API surface is stable and the backend changes are usually additive — new fields, not new endpoints.
Frequently asked questions
Does GraphQL replace REST?
No. REST endpoints stay useful for webhooks, server-to-server integrations, and CDN-cacheable read endpoints. GraphQL is the right tool for client-facing application APIs.
Will WPGraphQL keep my site secure?
WPGraphQL respects WordPress capability checks. A user with no permissions cannot query private data. Always test by querying as an anonymous user and confirming no protected fields leak.
How long did the AzanGuru backend take to build?
The core GraphQL schema and the first mobile screens were ready in about two weeks of full-time work. The mobile app itself took longer because of platform-specific work (in-app purchase, push notifications, store submissions).
Also read
- Case study: AzanGuru
- WordPress REST API: Building Headless WordPress with React
- Shipping a React Native App to Both App Stores
Need a mobile app backend on WordPress?
I have shipped this exact architecture. If you have a WordPress site that needs a clean mobile API, get in touch — we can scope whether WPGraphQL is the right tool for your case.