DEV Community

Zeyad Shalaby
Zeyad Shalaby

Posted on

Architecting a SaaS at 21: Why I Paired Laravel API with Next.js 14 (The Hybrid Stack)

I’m Zeyad, a 21-year-old CS student and Senior Full Stack Developer. Recently, I launched Najiz, a SaaS e-commerce platform built for the MENA region.

When starting a project of this scale, the biggest decision is the Tech Stack. The trend says "Go Full MERN" or "Go Full T3 Stack". But I took a different route. I chose a Hybrid Architecture.

Here is a breakdown of how I orchestrated Laravel, Next.js, Flutter, MongoDB, and Redis to build a scalable system.
🏗️ The High-Level Architecture

I didn't want a monolith. I wanted a decoupled system where the Backend serves as a "Truth Source" for multiple Frontends (Web & Mobile).

Backend: Laravel 11 (API Only)

Web Frontend: Next.js 14 (App Router)

Mobile App: Flutter

Database: MySQL (Relational) + MongoDB (Logs/Meta)

Caching/Queues: Redis
Enter fullscreen mode Exit fullscreen mode
  1. The Backbone: Laravel (API) 🛠️

Why PHP in 2026? Simple: Stability & Speed of Development. Laravel is not just a framework; it's an ecosystem. I used it strictly as a Headless CMS / API provider.

Authentication: I used Laravel Sanctum to handle token-based authentication for both the Next.js app and the Flutter mobile app seamlessly.

Eloquent ORM: Handling complex e-commerce relationships (Orders, Products, Variants, Shipping Zones) is a breeze with Eloquent compared to raw SQL or even Prisma.

Jobs & Queues: E-commerce needs background tasks (sending emails, processing payments). Laravel’s native Queue system paired with Redis handles this effortlessly.
Enter fullscreen mode Exit fullscreen mode

PHP

// Example: Dispatching a Job for Order Processing
OrderPlaced::dispatch($order)->onQueue('high-priority');

  1. The Face: Next.js 14 (Frontend) ⚡

For the user-facing storefronts, SEO is king. Client-Side Rendering (CSR) was not an option. I chose Next.js 14 for its robust Server-Side Rendering (SSR).

Dynamic Metadata: Every product page generates dynamic meta tags on the server for optimal indexing on Google.

Image Optimization: Using next/image to serve WebP images automatically, which is crucial for Core Web Vitals.

Performance: The dashboard feels like a SPA, but the storefronts are SEO-friendly static/SSR pages.
Enter fullscreen mode Exit fullscreen mode
  1. The Data Layer: Polyglot Persistence 🗄️

One database doesn't fit all use cases. I implemented a hybrid data strategy:

MySQL: Used for structured, relational data where ACID compliance is mandatory (Users, Orders, Transactions).

MongoDB: Used for unstructured data. For example, storing "Activity Logs" or dynamic "Product Attributes" that vary wildly between categories.

Redis: The glue. I use Redis for:

    Caching heavy database queries.

    Managing user sessions.

    Throttling API requests to prevent abuse.
Enter fullscreen mode Exit fullscreen mode
  1. Going Mobile with Flutter 📱

Since the backend is a pure API, building the mobile app was straightforward. Flutter consumes the same endpoints as the Next.js web app. This ensures that a feature added to the backend is immediately available to both web and mobile platforms without rewriting logic.
🚧 Challenges I Faced

It wasn't all smooth sailing.

CORS Hell: Managing Cross-Origin Resource Sharing between a Next.js app (on Vercel) and a Laravel API (on a VPS) required strict configuration.

State Synchronization: Ensuring that the cache in Redis invalidates correctly when a user updates a product in MySQL was tricky but solved using Model Observers.
Enter fullscreen mode Exit fullscreen mode

🚀 The Result

Najiz is now live in Beta. We have a system that is:

Scalable: We can scale the frontend and backend independently.

Fast: Thanks to Redis and Next.js SSR.

Maintainable: Separation of concerns makes debugging easier.
Enter fullscreen mode Exit fullscreen mode

I’d love to hear your thoughts on this stack. Would you have chosen Node.js for the backend? Let’s discuss in the comments! 👇

Live Demo: najiz.vercel.app

Top comments (0)