Expo, React Native, and Django form a practical stack for shipping Android and iOS applications from a shared codebase. Expo reduces native setup and release friction, React Native provides a productive mobile UI layer, and Django gives you a mature Python backend with authentication, admin workflows, ORM support, and a strong API ecosystem.
For an India-based startup or product team, this combination is especially useful when you need to validate a mobile product quickly without compromising on a backend that can support payments, logistics, education, health, or commerce workflows. The key is to treat the mobile app and Django service as two separately deployable products connected through a stable API contract.
When this stack is a good fit
Choose Expo React Native Django when:
- You want one mobile codebase for Android and iOS.
- Your team is comfortable with JavaScript or TypeScript on the client and Python on the server.
- The product needs relational data, role-based access, an admin panel, background jobs, or complex business rules.
- You want to start with a managed Expo workflow and add native capabilities only when required.
- You expect to integrate Indian services such as UPI payments, SMS-based login, GST invoices, regional languages, or domestic logistics providers.
Expo is not a backend and Django is not a mobile framework. Keep that boundary clear: Expo and React Native handle screens, device APIs, navigation, local state, and secure client storage; Django handles users, permissions, business rules, persistence, and API responses.
Recommended architecture
A production setup usually contains four layers:
1. Expo app: TypeScript screens, navigation, forms, local caching, push notifications, and device integrations.
2. Django API: Django REST Framework serializers, viewsets or API views, permissions, validation, and versioned endpoints.
3. Data and workers: PostgreSQL for durable data, Redis where caching or queues are needed, and a worker system such as Celery for email, notifications, reports, and webhooks.
4. Operations: HTTPS, environment-specific configuration, error tracking, database backups, monitoring, and CI/CD.
Django’s ORM and admin are valuable for internal operations, but do not expose the admin interface as a substitute for a customer-facing API. For larger products, follow the same separation and deployment discipline described in this guide to build scalable web applications with Django.
Set up the Django API
Create an isolated Python environment, install Django REST Framework, and add the applications required by your product:
python -m venv .venv
source .venv/bin/activate
pip install django djangorestframework django-cors-headers psycopg[binary]
django-admin startproject config .
python manage.py startapp accounts
python manage.py startapp productsConfigure PostgreSQL for staging and production rather than relying on SQLite. Define your data model early, including ownership, timestamps, status fields, and indexes for common queries. Use migrations as the source of truth and run them through deployment automation.
For APIs, define serializers that validate input and shape output deliberately. Do not return database models wholesale. Add pagination, filtering, ordering, and predictable error formats before the app grows. A response such as { "data": ..., "error": null, "meta": ... } can be useful if applied consistently, but consistency matters more than the exact envelope.
Use a versioned route such as /api/v1/products/. Versioning gives you room to evolve response fields without forcing every installed mobile client to update immediately.
Authentication and security
Mobile authentication needs more than a login screen. Use short-lived access tokens and rotating refresh tokens, or an established OAuth-compatible approach. Store sensitive tokens in Expo SecureStore, not ordinary AsyncStorage. On logout, revoke or invalidate refresh tokens where your threat model requires it.
Implement the following on the Django side:
- Password hashing through Django’s built-in authentication system.
- Rate limits for login, OTP, password reset, and sensitive actions.
- Object-level permissions so users cannot access another user’s records by changing an ID.
- Strict serializer validation for amounts, file types, phone numbers, and state transitions.
- HTTPS everywhere outside local development.
- Secret management through deployment environment variables or a managed secrets service.
- Audit logs for admin actions, payment changes, account recovery, and permission updates.
If you use phone-based authentication in India, design for OTP delivery failures, sender regulations, retries, and users who change numbers. Never treat the client as an authority for payment success, account status, or entitlements; confirm those events on the server through verified provider webhooks.
Build the Expo client
Start a current Expo project with TypeScript:
npx create-expo-app@latest mobile
cd mobile
npx expo startUse a clear client structure:
src/
api/ # HTTP client and endpoint functions
components/ # Reusable UI
features/ # Domain-specific screens and state
navigation/ # Auth and app navigators
storage/ # Secure and offline persistence
types/ # Shared client typesCreate one configured HTTP client rather than scattering URLs across components. Read the API base URL from environment-specific Expo configuration, add request timeouts, and map common server errors into user-readable messages. Handle loading, empty, offline, unauthorized, and retry states explicitly.
For a small app, React hooks and a focused context may be enough. For server state, consider a query library that provides caching, invalidation, retries, and optimistic updates. Keep server state separate from temporary form state and navigation state. Teams exploring richer React products can also review patterns in building full-stack LLM applications with React, even when the final product is not AI-first.
CORS, networking, and local development
Configure django-cors-headers carefully. Native apps do not behave exactly like browsers, and permissive CORS settings are not a security strategy. Allow only known web origins, while using authentication and server-side authorization for mobile API protection.
Local testing commonly fails because the phone cannot reach localhost on the developer’s laptop. Use the laptop’s LAN IP, an Expo tunnel, or a secure development tunnel. Make sure the Django server binds to an accessible interface and that the firewall allows the chosen port. Test on at least one physical Android device; emulators can hide network, camera, notification, and performance problems.
Testing and release workflow
Test the contract before polishing every screen. Add Django tests for permissions, validation, pagination, authentication, payment webhooks, and important state transitions. Add mobile tests for navigation guards, form validation, offline behaviour, and error recovery. A small set of end-to-end tests should cover signup, login, the core transaction, and logout.
Use separate development, staging, and production environments. Run linting, type checks, backend tests, migration checks, and dependency security scans in CI. Generate API documentation with OpenAPI so mobile and backend developers work from the same contract. Contract tests are particularly valuable when several teams or external vendors consume the API.
Expo Application Services can build and submit native binaries, while over-the-air updates are useful for JavaScript and asset changes that comply with Expo’s update rules. Do not use an OTA update to bypass a required native change, schema migration, permission change, or store review requirement. Maintain versioned release notes and a rollback plan.
Deployment checklist
For Django production:
- Deploy behind a reverse proxy or managed platform with HTTPS.
- Use PostgreSQL with automated backups and tested restoration.
- Serve media through object storage rather than the application container.
- Run workers separately from web processes when background work exists.
- Collect structured logs and application errors.
- Configure health checks, timeouts, and database connection limits.
- Restrict Django admin access with strong authentication and network controls.
For the Expo app:
- Configure Android and iOS identifiers, icons, splash assets, and permissions.
- Add privacy disclosures for location, camera, contacts, notifications, and analytics.
- Test release builds, not only Expo Go.
- Measure startup time, API latency, crash rates, and failed requests.
- Support slow networks and low-memory Android devices common across India.
Common mistakes to avoid
- Calling Django directly from every component instead of using an API layer.
- Hard-coding production URLs or secrets into the bundle.
- Assuming a successful client-side payment means the transaction is complete.
- Returning unpaginated lists that become slow on mobile networks.
- Ignoring timezone, currency, tax, and locale requirements.
- Shipping only on a high-end device and Wi-Fi.
- Making breaking API changes without supporting older app versions.
- Adding AI features before measuring whether they solve a real user problem. If AI is part of the roadmap, compare practical open-source alternatives to proprietary AI before committing to vendor costs and data policies.
FAQ
Is Expo mandatory for React Native?
No. Expo is optional, but its tooling, modules, build service, and update workflow make it a strong default for new applications. Move to a custom development build when your app needs native modules or configuration beyond the managed workflow.
Should Django expose REST or GraphQL?
Django REST Framework is usually the simpler starting point for mobile products. GraphQL can help when clients need flexible, nested data, but it adds schema, caching, authorization, and query-cost considerations.
Can this stack scale?
Yes, if you design clear APIs, index database queries, cache selectively, move slow work to workers, and monitor real usage. Scaling is an operational process, not a property guaranteed by choosing a framework.
What should I build first?
Define the core user journey, API contract, authentication model, and data ownership rules. Then ship one complete vertical slice—from Expo screen to Django database and back—before expanding features.