Building a mobile app is exciting. Keeping its backend from falling apart at scale is the hard part.
Most Laravel–React Native projects start cleanly — a few resource routes, token auth, and JSON responses. Then come push notifications, real-time feeds, file uploads, and thousands of concurrent users. By that point, the API that once felt tidy has become a maintenance burden: inconsistent response formats, bloated controllers, and authentication edge cases that only surface in production.
In 2026, React Native remains the top cross-platform mobile framework, and Laravel continues to be the backend of choice for rapid, well-structured API development. But pairing them well requires deliberate architectural decisions from day one.
The Problem: Why "Just Build Routes" Is Not Enough
A retail brand launched a React Native shopping app backed by Laravel. At 500 users, everything worked. At 50,000 users during a sale event, the app started throwing 504 timeouts, product images took 12 seconds to load, and the auth token refresh loop caused thousands of users to be silently logged out.
The root cause? No API versioning, no response caching strategy, eager-loaded queries returning 80+ fields per product, and tokens stored insecurely on the mobile client. The business impact was immediate: a 34% cart abandonment spike during peak hours and negative App Store reviews that took three months to recover from.
1. Project Structure: Separate Mobile API from Web Logic
The first principle is isolation. Mobile clients have different needs than web browsers — they need lean payloads, stable contracts, and versioned endpoints. Use a dedicated namespace and folder structure:
app/
Http/
Controllers/
Api/
V1/
AuthController.php
ProductController.php
Resources/
Api/
V1/
ProductResource.php
routes/
api_v1.php
api_v2.php
Register versioned route files in RouteServiceProvider:
Route::prefix('v1')->group(base_path('routes/api_v1.php'));
Route::prefix('v2')->group(base_path('routes/api_v2.php'));
2. Authentication: Sanctum Over Passport for Mobile
Laravel Passport adds OAuth2 complexity that most mobile apps do not need. Laravel Sanctum with token-based auth is the right choice for React Native — it is lighter, easier to rotate, and handles mobile token lifecycle cleanly.
public function login(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
'device_name' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
return response()->json(['message' => 'Invalid credentials'], 401);
}
$user->tokens()->where('name', $request->device_name)->delete();
return response()->json([
'token' => $user->createToken($request->device_name)->plainTextToken,
'user' => new UserResource($user),
]);
}
Always pass device_name from the React Native app. This lets users revoke individual device sessions — a feature security auditors require.
3. Consistent API Response Format
React Native developers should never have to guess the shape of a response. Standardise every success and error response using a base response trait:
trait ApiResponse
{
protected function success($data, $message = 'Success', $code = 200)
{
return response()->json([
'status' => true,
'message' => $message,
'data' => $data,
], $code);
}
protected function error($message, $code = 400, $errors = [])
{
return response()->json([
'status' => false,
'message' => $message,
'errors' => $errors,
], $code);
}
}
When every response follows the same shape, the React Native team can write a single Axios interceptor that handles errors globally — without touching every individual API call.
4. API Resources: Return Only What the Mobile App Needs
Never return Eloquent models directly. Always use API Resources to control exactly which fields reach the client. Over-returning data is one of the most common causes of slow mobile load times.
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->formatted_price,
'thumbnail'=> $this->thumbnail_url,
'in_stock' => $this->stock > 0,
// NOT: all 40 database columns, relationships, internal flags
];
}
5. Pagination Built for Mobile Scroll
Infinite scroll is the standard UX pattern in mobile apps. Use cursor-based pagination instead of page-based — it is more performant at scale and does not suffer from duplicate records when new items are inserted.
public function index(Request $request)
{
$products = Product::latest()
->cursorPaginate($request->get('per_page', 15));
return ProductResource::collection($products);
}
6. API Versioning Strategy
Version from day one, even if you only have one version. Adding versioning after launch requires coordinating a mobile app update — something you cannot force users to do.
- Use URL prefix versioning:
/api/v1/,/api/v2/ - Keep v1 stable while developing v2 in parallel
- Deprecate old versions with a
Deprecation-Noticeresponse header - Log which app versions are calling which API versions to know when it is safe to sunset
7. Rate Limiting and Throttling
Mobile users often have background refresh processes running alongside foreground requests. Without throttling, a single misbehaving app version can cause self-inflicted denial-of-service.
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});
RateLimiter::for('auth', function (Request $request) {
return Limit::perMinute(5)->by($request->ip());
});
Real Production Lessons
N+1 Queries Killing Mobile Performance
A product listing endpoint was taking 4.2 seconds on the server. Laravel Debugbar showed 180+ queries for a single request — each product was triggering individual queries for its category and brand. Fix: eager loading with ->with(['category', 'brand']) dropped query count to 3 and response time to 180ms — a 95.7% reduction.
Token Refresh Chaos
React Native stores tokens in AsyncStorage by default. After app updates, old tokens were sometimes cleared but the app still tried to use them, resulting in silent 401 loops. Fix: implement a token refresh endpoint and an Axios interceptor on the mobile side that automatically retries failed requests after refreshing the token.
Performance Win: HTTP Response Caching
Product catalogue data was being fetched fresh on every app open. Adding Laravel's response caching middleware for read-only endpoints (cache for 5 minutes, invalidated on product updates) reduced database load by 40% during peak hours.
Security Improvements
- Sanctum token scopes for role-based API access
- HTTPS enforced with HSTS headers — never send tokens over HTTP
- Input sanitisation middleware to strip unexpected fields from mobile payloads
- Rate limiting on auth endpoints to prevent brute force attacks
Conclusion
A Laravel API built for React Native is not just a web API with a mobile label. It requires deliberate decisions about response shape, authentication lifecycle, data volume, versioning, and performance — all made before the first user opens the app.
The practices in this guide come from building and fixing real production systems. The common thread: most problems are preventable with the right structure from the start.
Key takeaways: Version your API from day one, use Sanctum for mobile auth with device-specific tokens, always use API Resources to control payload size, implement cursor pagination for infinite scroll, and monitor your N+1 query situation before it becomes a production fire.