Skip to main content

Chat Next.js

The @pressw/chat-nextjs package provides Next.js-specific integrations for the @pressw/chat-core package. This separate package enables framework-agnostic use of chat-core while providing optimized Next.js functionality.

Features

  • Next.js Route Handlers: Pre-built API route handlers for thread management
  • Server Components: Optimized server-side rendering support
  • App Router: Full support for Next.js 13+ App Router
  • Type Safety: Full TypeScript support with Next.js specific types
  • SSR/SSG: Server-side and static generation compatibility
  • Middleware: Built-in authentication and tenant isolation
  • Error Handling: Next.js optimized error responses

Why a Separate Package?

By separating Next.js specific functionality from @pressw/chat-core, we enable:

  • Framework Agnostic Core: Use chat-core with Vite, Create React App, Expo, or any React framework
  • Optional Next.js Features: Only include Next.js dependencies when needed
  • Smaller Bundle Size: Core package stays lightweight without Next.js dependencies
  • Better Tree Shaking: Import only the functionality you need
  • Clear Separation: Framework-specific code is isolated and maintainable

Installation

bun add @pressw/chat-nextjs @pressw/chat-core
# or
npm install @pressw/chat-nextjs @pressw/chat-core
note

The @pressw/chat-nextjs package requires @pressw/chat-core as a peer dependency.

Quick Start

1. Set up your database adapter

First, configure your database adapter with @pressw/chat-core:

// lib/adapter.ts
import { createDrizzleAdapter } from '@pressw/chat-core/adapters';
import { db } from './db';

export const adapter = createDrizzleAdapter({ db });

2. Create route handlers

Use the pre-built route handlers for your API:

// app/api/chat/threads/route.ts
import { createThreadRouteHandlers } from '@pressw/chat-nextjs';
import { adapter } from '@/lib/adapter';
import { getUserContext } from '@/lib/auth';

const handlers = createThreadRouteHandlers({
adapter,
getUserContext,
});

export const GET = handlers.GET;
export const POST = handlers.POST;
// app/api/chat/threads/[id]/route.ts
import { createThreadDetailRouteHandlers } from '@pressw/chat-nextjs';
import { adapter } from '@/lib/adapter';
import { getUserContext } from '@/lib/auth';

const handlers = createThreadDetailRouteHandlers({
adapter,
getUserContext,
});

export const GET = handlers.GET;
export const PUT = handlers.PUT;
export const DELETE = handlers.DELETE;

3. Use React hooks in your components

// components/ThreadList.tsx
import { useThreads } from '@pressw/chat-core/react';

export function ThreadList() {
const { data, isLoading, error } = useThreads({
listOptions: { limit: 20 }
});

if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;

return (
<div>
{data?.threads.map((thread) => (
<div key={thread.id}>
<h3>{thread.title}</h3>
<p>{thread.createdAt.toLocaleDateString()}</p>
</div>
))}
</div>
);
}

API Routes

Thread Management Routes

The @pressw/chat-nextjs package provides three main types of route handlers:

Individual Route Handlers

For granular control over each endpoint:

// app/api/chat/threads/route.ts - List and create threads
export const { GET, POST } = createThreadRouteHandlers(config);

// app/api/chat/threads/[id]/route.ts - Single thread operations
export const { GET, PUT, DELETE } = createThreadDetailRouteHandlers(config);

Catch-All Route Handler

For simplified setup with a single route file:

// app/api/chat/[...route]/route.ts
import { createCatchAllThreadRouteHandler } from '@pressw/chat-nextjs';

const handler = createCatchAllThreadRouteHandler({
adapter,
getUserContext,
});

export const GET = handler;
export const POST = handler;
export const PUT = handler;
export const DELETE = handler;

Configuration

All route handlers accept a configuration object:

interface ThreadRouteConfig {
adapter: ChatCoreAdapter; // Database adapter
getUserContext: GetUserContextFn; // Authentication function
}

Authentication Function

Implement the getUserContext function to provide user authentication and multi-tenancy:

import { type GetUserContextFn } from '@pressw/chat-core';
import { NextRequest } from 'next/server';

export const getUserContext: GetUserContextFn = async (request: NextRequest) => {
// Extract user from session, JWT, etc.
const session = await getSession(request);

if (!session?.user) {
throw new Error('Unauthorized');
}

return {
userId: session.user.id,
organizationId: session.user.organizationId,
tenantId: session.user.tenantId,
};
};

Error Handling

The package provides standardized error responses following Next.js conventions:

interface ApiError {
error: string;
message: string;
code: string;
}

interface ApiResponse<T> {
success: boolean;
data?: T;
error?: ApiError;
}

Common error codes:

  • VALIDATION_ERROR (400) - Invalid request parameters
  • NOT_FOUND (404) - Thread not found
  • INTERNAL_ERROR (500) - Server error

Advanced Configuration

Custom Error Handling

Override default error handling:

import { createThreadRouteHandlers } from '@pressw/chat-nextjs';

const handlers = createThreadRouteHandlers({
adapter,
getUserContext,
onError: (error, request) => {
// Custom error logging
console.error('Thread API Error:', error);

// Custom error response
return NextResponse.json(
{
success: false,
error: {
error: 'Custom Error',
message: 'Something went wrong',
code: 'CUSTOM_ERROR',
},
},
{ status: 500 },
);
},
});

Request Validation

Add custom validation middleware:

const handlers = createThreadRouteHandlers({
adapter,
getUserContext,
middleware: {
beforeAuth: (request) => {
// Rate limiting, CORS, etc.
},
afterAuth: (request, userContext) => {
// Additional authorization checks
},
},
});

Response Transformation

Transform responses before sending:

const handlers = createThreadRouteHandlers({
adapter,
getUserContext,
transformResponse: (data, request) => {
// Add custom fields, filter sensitive data, etc.
return {
...data,
_timestamp: Date.now(),
_version: '1.0.0',
};
},
});

Server Components

Use threads in Server Components for SSR/SSG:

// app/threads/page.tsx
import { headers } from 'next/headers';
import { createThreadClient } from '@pressw/chat-nextjs/server';
import { adapter } from '@/lib/adapter';

export default async function ThreadsPage() {
const client = createThreadClient({
adapter,
request: { headers: headers() }
});

const threads = await client.listThreads({
limit: 20,
orderBy: 'updatedAt',
orderDirection: 'desc'
});

return (
<div>
<h1>Threads</h1>
{threads.threads.map((thread) => (
<div key={thread.id}>
<h2>{thread.title}</h2>
<p>Created: {thread.createdAt.toLocaleDateString()}</p>
</div>
))}
</div>
);
}

Middleware Integration

Integrate with Next.js middleware for authentication:

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
// Check authentication for chat API routes
if (request.nextUrl.pathname.startsWith('/api/chat')) {
const token = request.headers.get('authorization');

if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
}

return NextResponse.next();
}

export const config = {
matcher: '/api/chat/:path*',
};

Performance Optimization

Caching

Enable caching for read operations:

// app/api/chat/threads/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
const response = await handlers.GET(request);

// Add cache headers
response.headers.set('Cache-Control', 's-maxage=60, stale-while-revalidate');

return response;
}

Edge Runtime

Use Edge Runtime for better performance:

// app/api/chat/threads/route.ts
export const runtime = 'edge';

import { createThreadRouteHandlers } from '@pressw/chat-nextjs/edge';

Migration from Chat Core

If you're currently using Next.js route handlers from @pressw/chat-core, here's how to migrate:

Before (chat-core)

import { createThreadRouteHandlers } from '@pressw/chat-core/nextjs';

After (chat-nextjs)

import { createThreadRouteHandlers } from '@pressw/chat-nextjs';

The API remains the same, but you'll need to:

  1. Install @pressw/chat-nextjs
  2. Update your imports
  3. Ensure @pressw/chat-core is installed as a peer dependency

Best Practices

1. Environment-Specific Configuration

// lib/config.ts
const config = {
development: {
enableDebugLogging: true,
cors: { origin: '*' },
},
production: {
enableDebugLogging: false,
cors: { origin: 'https://yourdomain.com' },
},
};

export const threadConfig = config[process.env.NODE_ENV];

2. Type Safety

Always use TypeScript for better developer experience:

import type { Thread, CreateThreadOptions } from '@pressw/chat-core';
import type { NextRequest } from 'next/server';

export async function createThread(
options: CreateThreadOptions,
request: NextRequest,
): Promise<Thread> {
// Implementation
}

3. Error Boundaries

Use React Error Boundaries with your thread components:

'use client';

import { ErrorBoundary } from 'react-error-boundary';
import { ThreadList } from './ThreadList';

function ErrorFallback({ error }: { error: Error }) {
return (
<div className="error-boundary">
<h2>Something went wrong:</h2>
<pre>{error.message}</pre>
</div>
);
}

export function ThreadListPage() {
return (
<ErrorBoundary FallbackComponent={ErrorFallback}>
<ThreadList />
</ErrorBoundary>
);
}

Compatibility

  • Next.js: 14.0+ or 15.0+ (App Router required)
  • React: 18.0+ (optional - only needed for Client Components)
  • TypeScript: 5.0+ (recommended)
  • Node.js: 18.0+ (for server-side functionality)

Next Steps