# How the Dify Chat Platform Is Built with Next.js 15 App Router

> Discover how Dify Chat is built with Next.js 15 App Router. Learn about React Server Components, Route Handlers, and Next-Auth for a unified full-stack experience.

- Repository: [lexmin0412/dify-chat](https://github.com/lexmin0412/dify-chat)
- Tags: architecture
- Published: 2026-03-06

---

**The Dify Chat platform is a full-stack web application built on Next.js 15 using the App Router architecture, leveraging React Server Components for server-side rendering, Route Handlers for type-safe API endpoints, and Next-Auth for integrated authentication—all within a single codebase without requiring a separate backend server.**

The Dify Chat platform delivers a modern chat interface for managing Dify AI applications and users. Built using Next.js 15 and the App Router paradigm, the platform treats every route as either a React Server Component (RSC) or a client component, enabling server-only code execution, streamlined data fetching, and API routes without the complexity of a separate Express server.

## App Router Architecture and File Conventions

The platform follows Next.js 15 App Router file conventions where the `app/` directory defines both UI routes and API endpoints. Every folder containing a [`page.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/page.tsx) file becomes a navigable route, while folders containing a [`route.ts`](https://github.com/lexmin0412/dify-chat/blob/main/route.ts) file become API endpoints. This co-location allows server-side logic to live alongside the components that consume it.

In [`app/layout.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/app/layout.tsx), the root layout defines the global HTML structure and wraps the application in providers:

```tsx
// packages/platform/app/layout.tsx
import './globals.css';
import { SessionProvider } from '@/components/auth/session-provider';
import ThemeProvider from '@/components/theme-provider';

export const metadata = {
  title: 'Dify Chat Platform',
  description: 'Manage Dify apps & users',
};

export default function RootLayout({
  children,
}: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <SessionProvider>
          <ThemeProvider>{children}</ThemeProvider>
        </SessionProvider>
      </body>
    </html>
  );
}

```

This file establishes the SessionProvider for Next-Auth and a custom ThemeProvider, ensuring authentication and styling contexts are available throughout the component tree.

## Page Routing and Server Components

The platform uses nested folders under `app/` to define distinct UI screens. Each [`page.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/page.tsx) exports a React Server Component by default, enabling data fetching to occur on the server before HTML is sent to the browser.

Key routes include:

- **[`app/page.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/app/page.tsx)** – The dashboard home screen
- **[`app/login/page.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/app/login/page.tsx)** – Authentication entry point
- **[`app/app-management/page.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/app/app-management/page.tsx)** – Console for managing Dify applications

Server Components in these files can directly import server-only modules like the Prisma client without exposing database connection details to the client bundle. This architecture eliminates API boilerplate for data that doesn't require client interactivity.

## API Routes and Route Handlers

For client-side interactivity and external API proxying, the platform implements Route Handlers using [`route.ts`](https://github.com/lexmin0412/dify-chat/blob/main/route.ts) files. These handlers run on the server, have direct access to environment variables and database clients, and return typed JSON responses.

The Dify workflow proxy endpoint demonstrates this pattern:

```ts
// packages/platform/app/api/client/dify/[appId]/workflows/run/route.ts
import { NextResponse } from 'next/server';
import { getDifyClient } from '@/lib/api-utils';

export async function POST(request: Request, { params }: { params: { appId: string } }) {
  const client = getDifyClient();
  const { inputs } = await request.json();
  const result = await client.runWorkflow(params.appId, inputs);
  return NextResponse.json(result);
}

```

This handler receives JSON payloads from the browser, forwards them to the Dify backend using a utility client, and returns the workflow execution results. The dynamic segment `[appId]` enables the same handler to serve multiple Dify applications based on the URL path.

## Authentication Implementation

The platform uses Next-Auth for session management, integrated via a catch-all Route Handler at `app/api/auth/[...nextauth]/route.ts`. This file creates a NextAuth.js handler that issues JWT-based sessions and persists user data via Prisma.

The authentication flow connects to the root layout through [`components/auth/session-provider.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/components/auth/session-provider.tsx), which exposes the session context to the React tree. For route protection, [`components/auth/auth-guard.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/components/auth/auth-guard.tsx) implements a client-side guard:

```tsx
// packages/platform/components/auth/auth-guard.tsx
'use client';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';

export default function AuthGuard({ children }: { children: React.ReactNode }) {
  const { data: session, status } = useSession();
  const router = useRouter();

  useEffect(() => {
    if (status === 'unauthenticated') router.push('/login');
  }, [status, router]);

  if (status === 'loading') return <p>Loading...</p>;
  return <>{session ? children : null}</>;
}

```

Wrapping page components with `<AuthGuard>` ensures only authenticated users can access protected routes, redirecting unauthenticated sessions to the login page.

## Database Layer with Prisma

Data persistence uses Prisma as the ORM. The Prisma client is instantiated in [`lib/prisma.ts`](https://github.com/lexmin0412/dify-chat/blob/main/lib/prisma.ts) and imported by Route Handlers and Server Components that require database access. This centralization ensures connection pooling and prevents multiple client instances in development.

Server-side code can query the database directly without exposing connection strings to the browser, leveraging the natural server-only boundary of React Server Components and Route Handlers.

## Component Architecture and Styling

The UI is built with a hybrid component strategy. **Server Components** in `components/layout/` handle static markup and data fetching, while **Client Components** in `components/ui/` manage interactive elements using React hooks.

Styling uses Tailwind CSS v4, configured in `postcss.config.mjs` and imported globally via [`app/globals.css`](https://github.com/lexmin0412/dify-chat/blob/main/app/globals.css). The design system tokens reside under `theme/` and are consumed by platform components for consistent spacing, colors, and typography.

## Configuration and Build Setup

The Next.js configuration in [`next.config.ts`](https://github.com/lexmin0412/dify-chat/blob/main/next.config.ts) enables the App Router (`appDir`), experimental Server Actions, and custom rewrites for proxying Dify API requests. It also configures image optimization domains and webpack customizations required by the platform.

This configuration file serves as the central control point for runtime behavior, build-time optimizations, and experimental feature flags.

## Summary

- **Next.js 15 App Router** powers the entire platform, enabling file-system based routing for both UI pages and API endpoints without a separate backend server.
- **React Server Components** render pages on the server by default, allowing direct database access via Prisma and improving initial page load performance.
- **Route Handlers** in [`app/api/.../route.ts`](https://github.com/lexmin0412/dify-chat/blob/main/app/api/.../route.ts) provide type-safe API endpoints that proxy requests to the Dify backend and handle authentication.
- **Next-Auth** integrates via a dynamic catch-all route, providing JWT-based sessions consumed by the `SessionProvider` and protected by the `AuthGuard` component.
- **Tailwind CSS v4** and a hybrid server/client component architecture deliver a responsive, maintainable UI with clear boundaries between static and interactive elements.

## Frequently Asked Questions

### How does the Dify Chat platform handle server-side data fetching?

The platform leverages **React Server Components** (RSCs) by default in the App Router. Server Components in files like [`app/page.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/app/page.tsx) can directly import the Prisma client from [`lib/prisma.ts`](https://github.com/lexmin0412/dify-chat/blob/main/lib/prisma.ts) and execute database queries during rendering. This happens entirely on the server, so database connection strings never reach the browser, and the HTML sent to the client already contains the fetched data.

### What is the difference between Route Handlers and Server Components in this architecture?

**Server Components** (defined in [`page.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/page.tsx) files) render UI and can fetch data, but they respond to browser navigation requests and return HTML. **Route Handlers** (defined in [`route.ts`](https://github.com/lexmin0412/dify-chat/blob/main/route.ts) files inside `app/api/`) handle HTTP requests directly and return JSON or other data formats. Route Handlers are used for client-side API calls, webhooks, and proxying requests to external services like the Dify backend, while Server Components handle the initial page render.

### How is authentication protected across different routes?

The platform uses a combination of **Next-Auth** and client-side guards. The `SessionProvider` in [`app/layout.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/app/layout.tsx) makes session data available throughout the component tree. For routes requiring authentication, the `AuthGuard` component in [`components/auth/auth-guard.tsx`](https://github.com/lexmin0412/dify-chat/blob/main/components/auth/auth-guard.tsx) checks the session status. If the user is unauthenticated, it redirects to `/login` using the Next.js router. This pattern allows fine-grained control over which pages are public and which require a valid session.

### Where does the platform configure API proxying to the Dify backend?

API proxying is configured in two places. First, **Route Handlers** in `app/api/client/dify/[appId]/workflows/run/route.ts` handle specific endpoint proxying by receiving requests, forwarding them to the Dify API using the `getDifyClient` utility, and returning the results. Second, **rewrites** in [`next.config.ts`](https://github.com/lexmin0412/dify-chat/blob/main/next.config.ts) can configure URL pattern matching to proxy requests at the edge level before they reach the application code, though the primary implementation uses the explicit Route Handler pattern for type safety and direct Prisma integration.