Skip to main content
npayload is launching soon.
npayloadDocs
Framework Quickstarts

Next.js quickstart

Integrate npayload with Next.js App Router using server actions and React hooks

Add real-time messaging to a Next.js App Router application using @npayload/node for server-side operations and @npayload/react for client-side hooks.

Prerequisites

  • Next.js 14+ with App Router
  • An npayload account with machine credentials (get them here)

Install the SDKs

npm install @npayload/node @npayload/react @npayload/js

Add credentials to .env.local:

NPAYLOAD_CLIENT_ID=oac_your_client_id
NPAYLOAD_HMAC_SECRET=your_hmac_secret
NEXT_PUBLIC_NPAYLOAD_KEY=pk_live_your_publishable_key

Create the server client

// lib/npayload.ts
import { NPayloadAuth, NPayloadClient } from '@npayload/node';

const auth = new NPayloadAuth({
  clientId: process.env.NPAYLOAD_CLIENT_ID!,
  hmacSecret: process.env.NPAYLOAD_HMAC_SECRET!,
});

export const npayload = new NPayloadClient({ auth });

Add the React provider

// app/providers.tsx
'use client';

import { NPayloadProvider } from '@npayload/react';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <NPayloadProvider
      config={{
        publishableKey: process.env.NEXT_PUBLIC_NPAYLOAD_KEY!,
      }}
    >
      {children}
    </NPayloadProvider>
  );
}
// app/layout.tsx
import { Providers } from './providers';

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

Create a server action for publishing

// app/actions.ts
'use server';

import { npayload } from '@/lib/npayload';

export async function publishMessage(channel: string, payload: unknown) {
  const message = await npayload.messages.publish({ channel, payload });
  return { messageId: message.gid };
}

Build the page with real-time updates

// app/page.tsx
'use client';

import { useMessages, usePublish } from '@npayload/react';
import { publishMessage } from './actions';

export default function Home() {
  const { messages, isLoading } = useMessages('notifications');
  const { publish, isPublishing } = usePublish('notifications');

  const handlePublish = async () => {
    await publishMessage('notifications', {
      event: 'greeting',
      message: 'Hello from Next.js!',
      timestamp: new Date().toISOString(),
    });
  };

  return (
    <main>
      <h1>npayload + Next.js</h1>

      <button onClick={handlePublish} disabled={isPublishing}>
        {isPublishing ? 'Publishing...' : 'Publish message'}
      </button>

      <h2>Messages</h2>
      {isLoading ? (
        <p>Loading...</p>
      ) : (
        <ul>
          {messages.map((msg) => (
            <li key={msg.gid}>
              {JSON.stringify(msg.payload)}
            </li>
          ))}
        </ul>
      )}
    </main>
  );
}

Add a webhook route

// app/api/webhooks/npayload/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { npayload } from '@/lib/npayload';

export async function POST(req: NextRequest) {
  const body = await req.json();
  const signature = req.headers.get('x-npayload-signature')!;

  const isValid = npayload.webhooks.verify(
    body,
    signature,
    process.env.WEBHOOK_SECRET!
  );

  if (!isValid) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
  }

  // Process the webhook
  console.log('Webhook received:', body.payload);

  return NextResponse.json({ received: true });
}

Next steps

Was this page helpful?

On this page