Home About Skills Products Work
Projects Services Experience
Learn
Tutorials Courses Blogs Resources
Contact
Blog · Next.js

Building a Full-Stack Next.js App with a Laravel API Backend

Building a Full-Stack Next.js App with a Laravel API Backend

A common, production-realistic architecture: Laravel handles the database, business logic, and auth as a pure JSON API, while Next.js handles the frontend, SEO, and rendering. Here's how the pieces actually connect.

Why Split Them at All

Laravel is excellent at data modeling, queues, and admin tooling. Next.js is excellent at fast, SEO-friendly rendering and a modern component-driven UI. Keeping them separate also means you can build a mobile app against the exact same API later with zero backend changes.

Laravel Side: A Clean JSON API

Expose your resources via routes/api.php, protected with Sanctum for authenticated routes, and make sure CORS is configured so your Next.js domain is allowed to call it:

// config/cors.php
'allowed_origins' => ['https://myapp.com'],
'supports_credentials' => true,

Next.js Side: Fetching From Laravel

async function getPosts() {
  const res = await fetch(`${process.env.API_URL}/api/posts`, {
    next: { revalidate: 300 },
  });
  if (!res.ok) throw new Error('Failed to fetch posts');
  return res.json();
}

export default async function BlogPage() {
  const posts = await getPosts();
  return <PostGrid posts={posts} />;
}

Keep the Laravel API URL in an environment variable, never hardcoded — it will differ between local, staging, and production.

Handling Authentication Across Domains

For a token-based flow (recommended when frontend and backend are on different domains), the Next.js app calls Laravel's Sanctum login endpoint, stores the returned token server-side (in an HTTP-only cookie set by a Next.js Route Handler), and attaches it as a Bearer token on subsequent API calls — never exposing the raw token to client-side JavaScript.

Revalidating Content on Publish

When an admin publishes a new post in Laravel, you don't want to wait for the cache to expire naturally. Laravel can call Next.js's on-demand revalidation endpoint right after saving:

Http::post('https://myapp.com/api/revalidate', [
    'secret' => config('services.nextjs.revalidate_secret'),
    'path' => '/blog',
]);

Deployment Shape

In practice this usually means: Laravel deployed to a VPS or Forge/Vapor, Next.js deployed to Vercel (or the same server via a Node process), and a shared .env-driven API URL tying them together. Two codebases, two deploys, one product.

Next.js for Beginners: App Router vs Pages Router

Next.js for Beginners: App Router vs Pages Router

What actually changed between the Pages Router and the App Router, and which one to use for a new project in 2026.

Fetching Data in Next.js: Server Components, Client Components, and Caching

Fetching Data in Next.js: Server Components, Client Components, and Caching

The mental model that actually explains Next.js data fetching — where to fetch, when to cache, and how streaming works.

Esc