Looking for the chatbot template? It's now here.

Slack bot with Next.js and Redis

This guide walks through building a Slack bot with Next.js, covering project setup, Slack app configuration, event handling, interactive features, and deployment.

Prerequisites

  • Node.js 18+
  • pnpm (or npm/yarn)
  • A Slack workspace where you can install apps
  • A Redis instance for state management

Create a Next.js app

Scaffold a new Next.js project and install Chat SDK dependencies:

Terminal
npx create-next-app@latest my-slack-bot --typescript --app
cd my-slack-bot
pnpm add chat @chat-adapter/slack @chat-adapter/state-redis

Create a Slack app

  1. Go to api.slack.com/apps
  2. Click Create New App then From an app manifest
  3. Select your workspace and paste the following manifest:
slack-manifest.yml
display_information:
  name: My Bot
  description: A bot built with Chat SDK

features:
  bot_user:
    display_name: My Bot
    always_online: true

oauth_config:
  scopes:
    bot:
      - app_mentions:read
      - channels:history
      - channels:read
      - chat:write
      - groups:history
      - groups:read
      - im:history
      - im:read
      - mpim:history
      - mpim:read
      - reactions:read
      - reactions:write
      - users:read

settings:
  event_subscriptions:
    request_url: https://your-domain.com/api/webhooks/slack
    bot_events:
      - app_mention
      - message.channels
      - message.groups
      - message.im
      - message.mpim
  interactivity:
    is_enabled: true
    request_url: https://your-domain.com/api/webhooks/slack
  org_deploy_enabled: false
  socket_mode_enabled: false
  token_rotation_enabled: false
  1. Replace https://your-domain.com/api/webhooks/slack with your deployed webhook URL
  2. Click Create

Get credentials

After creating the app:

  1. Go to OAuth & Permissions, click Install to Workspace, and copy the Bot User OAuth Token (xoxb-...) — you'll need this as SLACK_BOT_TOKEN
  2. Go to Basic InformationApp Credentials and copy the Signing Secret — you'll need this as SLACK_SIGNING_SECRET

Configure environment variables

Create a .env.local file in your project root:

.env.local
SLACK_BOT_TOKEN=xoxb-your-bot-token
SLACK_SIGNING_SECRET=your-signing-secret
REDIS_URL=redis://localhost:6379

Create the bot

Create lib/bot.ts with a Chat instance configured with the Slack adapter:

lib/bot.ts
import { Chat } from "chat";
import { createSlackAdapter } from "@chat-adapter/slack";
import { createRedisState } from "@chat-adapter/state-redis";

export const bot = new Chat({
  userName: "mybot",
  adapters: {
    slack: createSlackAdapter(),
  },
  state: createRedisState(),
});

// Respond when someone @mentions the bot
bot.onNewMention(async (thread) => {
  await thread.subscribe();
  await thread.post("Hello! I'm listening to this thread now.");
});

// Respond to follow-up messages in subscribed threads
bot.onSubscribedMessage(async (thread, message) => {
  await thread.post(`You said: ${message.text}`);
});

The adapter auto-detects SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET from your environment, and createRedisState() reads REDIS_URL automatically.

onNewMention fires when a user @mentions your bot. Calling thread.subscribe() tells the SDK to track that thread, so subsequent messages trigger onSubscribedMessage.

Create the webhook route

Create a dynamic API route that handles incoming webhooks:

app/api/webhooks/[platform]/route.ts
import { after } from "next/server";
import { bot } from "@/lib/bot";

type Platform = keyof typeof bot.webhooks;

export async function POST(
  request: Request,
  context: RouteContext<"/api/webhooks/[platform]">
) {
  const { platform } = await context.params;

  const handler = bot.webhooks[platform as Platform];
  if (!handler) {
    return new Response(`Unknown platform: ${platform}`, { status: 404 });
  }

  return handler(request, {
    waitUntil: (task) => after(() => task),
  });
}

This creates a POST /api/webhooks/slack endpoint. The waitUntil option ensures message processing completes after the HTTP response is sent — required on serverless platforms where the function would otherwise terminate before your handlers finish.

Test locally

  1. Start your development server (pnpm dev)
  2. Expose it with a tunnel (e.g. ngrok http 3000)
  3. Update the Slack Event Subscriptions Request URL to your tunnel URL
  4. Invite your bot to a Slack channel (/invite @mybot)
  5. @mention the bot — it should respond with "Hello! I'm listening to this thread now."
  6. Reply in the thread — it should echo your message back

Add interactive features

Chat SDK supports rich interactive messages using a JSX-like syntax. Update your bot to send cards with buttons:

lib/bot.ts
import { Chat, Card, CardText as Text, Actions, Button, Divider } from "chat";
import { createSlackAdapter } from "@chat-adapter/slack";
import { createRedisState } from "@chat-adapter/state-redis";

export const bot = new Chat({
  userName: "mybot",
  adapters: {
    slack: createSlackAdapter(),
  },
  state: createRedisState(),
});

bot.onNewMention(async (thread) => {
  await thread.subscribe();
  await thread.post(
    <Card title="Welcome!">
      <Text>I'm now listening to this thread. Try clicking a button:</Text>
      <Divider />
      <Actions>
        <Button id="hello" style="primary">Say Hello</Button>
        <Button id="info">Show Info</Button>
      </Actions>
    </Card>
  );
});

bot.onAction("hello", async (event) => {
  await event.thread.post(`Hello, ${event.user.fullName}!`);
});

bot.onAction("info", async (event) => {
  await event.thread.post(`You're on ${event.thread.adapter.name}.`);
});

The file extension must be .tsx (not .ts) when using JSX components like Card and Button. Make sure your tsconfig.json has "jsx": "react-jsx" and "jsxImportSource": "chat".

Deploy to Vercel

Deploy your bot to Vercel:

Terminal
vercel deploy

After deployment, set your environment variables in the Vercel dashboard (SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET, REDIS_URL). If your manifest used a placeholder URL, update the Event Subscriptions and Interactivity Request URLs in your Slack app settings to your production URL.

Next steps

  • Cards — Build rich interactive messages with buttons, fields, and selects
  • Modals — Open forms and dialogs from button clicks
  • Streaming — Stream AI-generated responses to chat
  • Actions — Handle button clicks, select menus, and other interactions
  • Slack adapter — Multi-workspace OAuth, token encryption, and full configuration reference