Client Area

Building Backend APIs for Mobile Apps (iOS, Android, Flutter) on DomainIndia Hosting

ByDomain India Team·DomainIndia Engineering
6 min readPublished 21 Apr 2026Updated 23 Jun 2026162 views

In this article

  • 1What mobile backends must handle
  • 2Which DomainIndia plan?
  • 3Choosing the API style
  • 4Authentication patterns
  • 5Pattern 1 — JWT with refresh tokens

Building Backend APIs for Mobile Apps (iOS, Android, Flutter) on DomainIndia Hosting

TL;DR
Mobile apps need a backend. This guide covers REST vs GraphQL for mobile, authentication (JWT, OAuth, biometric), push notifications (FCM + APNs), file uploads, offline sync, and choosing the right DomainIndia hosting tier for your app's stage.

What mobile backends must handle

Every mobile app (iOS, Android, React Native, Flutter) talks to a backend for:

  • User signup / login (email, Google, Apple, phone OTP)
  • Content feeds — loaded lazily, paginated
  • File uploads (profile photos, documents, audio)
  • Push notifications
  • Real-time updates (chat, live scores, order tracking)
  • Analytics events
  • Payments (Razorpay/Stripe for Indian + global markets)
  • Offline sync (app works without internet, syncs on reconnect)

Which DomainIndia plan?

App stageMAU (monthly active users)Recommended plan
Prototype / testing<1,000Shared cPanel with Node.js or Laravel
MVP / growing1,000 – 10,000VPS Starter (2 GB)
Production / scaling10,000 – 100,000VPS Business (4 GB) + Cloudflare CDN
High-scale100,000+Multi-VPS + load balancer + managed PostgreSQL

Mobile backends are API-only (no HTML rendering), so they're efficient. A 2 GB VPS easily handles 10,000 MAU for a typical social/commerce app.

Choosing the API style

REST — simple, works everywhere, easy caching. Best default.

GraphQL — thin clients love minimal payloads over 3G. See our GraphQL APIs article.

gRPC — internal microservices; rarely used client-side for mobile (except streaming/IoT).

WebSockets / Server-Sent Events — real-time (chat, live trackers).

For most Indian apps: REST with JSON + WebSockets for real-time features. Add GraphQL only if you have multiple mobile platforms with different field needs.

Authentication patterns

Pattern 1 — JWT with refresh tokens

Classic for mobile. Apps can't keep a cookie-based session easily.

  1. User logs in with email + password (or social OAuth)
  2. Backend issues:

- Short-lived access token (15 min)

- Long-lived refresh token (30 days), stored encrypted on device

  1. Every API call sends Authorization: Bearer <access_token>
  2. Before expiry, app POSTs refresh token → gets new access token
  3. Refresh token can be revoked server-side (logout all devices)

Node.js example:

javascript
import jwt from 'jsonwebtoken';

function issueTokens(userId) {
  const accessToken = jwt.sign({ sub: userId }, ACCESS_SECRET, { expiresIn: '15m' });
  const refreshToken = jwt.sign({ sub: userId, type: 'refresh' }, REFRESH_SECRET, { expiresIn: '30d' });
  // Store hash of refresh token in DB for revocation
  db.refreshToken.create({ userId, hash: sha256(refreshToken), expiresAt: ... });
  return { accessToken, refreshToken };
}

// Client calls POST /auth/refresh with the refresh token:
app.post('/auth/refresh', async (req, res) => {
  const { refreshToken } = req.body;
  const payload = jwt.verify(refreshToken, REFRESH_SECRET);
  const stored = await db.refreshToken.findFirst({ where: { hash: sha256(refreshToken) } });
  if (!stored || stored.revoked) return res.status(401).json({ error: 'Invalid' });
  res.json(issueTokens(payload.sub));
});

Pattern 2 — OAuth (Sign in with Apple / Google)

Mandatory for iOS apps that offer any other login (App Store rule). Google Sign-In covers Android.

  • iOS: Apple Sign-In, returns identity token, verify signature against Apple's JWK
  • Android: Google Sign-In, same pattern with Google JWK

Your backend stores a provider + providerUserId → internalUserId mapping.

Pattern 3 — Biometric unlock (local)

Device unlocks the refresh token using FaceID / fingerprint, then sends it to your API. Your API doesn't know or care about biometrics — it just sees refresh → access.

Push notifications

Two providers: Firebase Cloud Messaging (FCM) for Android + cross-platform, Apple Push Notification service (APNs) for iOS.

Easiest path: use FCM for both. Firebase handles APNs relay for you.

  1. Create Firebase project, add iOS + Android apps
  2. Download google-services.json (Android) + GoogleService-Info.plist (iOS)
  3. App registers with FCM on first launch → gets device token → POSTs to your /push/register endpoint
  4. Backend stores userId ↔ deviceToken mapping
  5. To notify:

```bash

curl -X POST https://fcm.googleapis.com/v1/projects/YOUR_PROJECT/messages:send

-H "Authorization: Bearer $ACCESS_TOKEN"

-H "Content-Type: application/json"

-d '{"message":{"token":"DEVICE_TOKEN","notification":{"title":"Order shipped","body":"Track now"}}}'

```

Libraries: firebase-admin (Node), pyfcm (Python), kreait/firebase-php.

File uploads

Mobile devices upload photos, videos, documents. Strategies:

Direct-to-S3 (or Backblaze B2) with presigned URLs — recommended.

  • Client requests POST /upload-url with filename + content-type
  • Backend returns a 10-minute signed URL to upload directly to S3
  • Client PUTs the file to S3; no hop through your API
  • Client notifies backend with the final S3 key

Saves your VPS bandwidth + CPU. Scales infinitely.

Through-your-API upload — only for small files (<5 MB). Simpler but consumes VPS RAM/bandwidth.

javascript
import multer from 'multer';
const upload = multer({ limits: { fileSize: 5 * 1024 * 1024 }, dest: '/tmp/' });
app.post('/upload', upload.single('file'), async (req, res) => {
  const key = `users/${req.user.id}/${Date.now()}-${req.file.originalname}`;
  await s3.putObject({ Bucket: 'uploads', Key: key, Body: fs.createReadStream(req.file.path) });
  res.json({ url: `https://cdn.yourcompany.com/${key}` });
});

Offline sync

Users in India's metro-to-tier-2 transitions (weak 4G, metro tunnels) demand offline-first apps.

Patterns:

  1. Optimistic writes — app writes to local SQLite first, then syncs. Show "syncing..." indicator.
  2. Pull-based sync with timestampsGET /sync?since=<last_sync_at> returns changes. Client applies.
  3. Realm / WatermelonDB / PowerSync — libraries that handle sync for you.

Backend needs:

  • updatedAt timestamp on every row (auto-update on change)
  • Soft deletes (flag deletedAt, don't hard-delete)
  • Tombstone endpoint listing deleted IDs since timestamp

Payments (Indian market)

Primary: Razorpay (UPI, cards, netbanking, wallets, subscriptions). Alternative: Stripe (cards, international).

Mobile integration uses their official SDKs — your backend creates the order on Razorpay API, passes order ID to app, app opens Razorpay Checkout, app sends signature back to backend for verification. See our Razorpay Integration article.

Versioning your API

Mobile apps don't auto-update — expect users running 6-month-old app versions for years.

Pattern: version your API URL (/v1/, /v2/) and keep old versions running indefinitely.

GET /v1/feed   # legacy — keep forever
GET /v2/feed   # current
GET /v3/feed   # next

If you can't maintain N versions forever, use feature-flagged responses keyed by the User-Agent or a custom X-App-Version header.

Security essentials

FAQ

Q Can I host a mobile backend on shared cPanel?

Yes for prototypes and small apps (<1K users). Node.js via Setup Node.js App, or Laravel/Rails for traditional stacks. For serious traffic, upgrade to VPS.

Q Do I need a separate dev / staging / production?

Yes. Mobile apps can't "hotfix" server bugs — apps run against whatever backend version they target. Never point new app builds at production until tested on staging.

Q How much does mobile backend cost at 100K users?

Typical stack on DomainIndia: VPS Business (~₹3,000/mo) + PostgreSQL managed or self-hosted + S3-compatible storage (~₹500/mo) + Cloudflare Free + FCM Free = ~₹4,000/mo total. Scales linearly with active usage.

Q React Native vs Flutter vs native — does the backend change?

No. Your API is stack-agnostic. Pick frontend based on team skills. Backend stays the same.

Q Should I use Firebase instead of a custom backend?

Firebase is faster to launch (auth, DB, push, storage bundled) but vendor-locked and costly past ~10K MAU. Custom on DomainIndia gives you full control and predictable costs.

Build your mobile API with predictable costs and full control. See our VPS plans

Was this article helpful?

Your feedback helps us improve our documentation

Still need help? Submit a support ticket