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

Creating a Chat Instance

Initialize the Chat class with adapters, state, and configuration options.

The Chat class is the main entry point for your bot. It coordinates adapters, routes events to your handlers, and manages thread state.

Basic setup

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

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

bot.onNewMention(async (thread) => {
  await thread.subscribe();
  await thread.post("Hello! I'm listening to this thread.");
});

This example uses Redis. Chat SDK also supports PostgreSQL and ioredis as production state adapters. See State Adapters for all options.

Each adapter factory auto-detects credentials from environment variables (SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET, REDIS_URL, etc.), so you can get started with zero config. Pass explicit values to override.

Multiple adapters

Register multiple adapters to deploy your bot across platforms simultaneously:

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

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

Your event handlers work identically across all registered adapters — the SDK normalizes messages, threads, and reactions into a consistent format.

Configuration options

OptionTypeDefaultDescription
userNamestringrequiredDefault bot username across all adapters
adaptersRecord<string, Adapter>requiredMap of adapter name to adapter instance
stateStateAdapterrequiredState adapter for subscriptions and locking
loggerLogger | LogLevel"info"Logger instance or log level ("debug", "info", "warn", "error", "silent")
dedupeTtlMsnumber300000TTL in ms for message deduplication (5 minutes)
streamingUpdateIntervalMsnumber500Update interval in ms for post+edit streaming
fallbackStreamingPlaceholderTextstring | null"..."Placeholder text while streaming starts. Set to null to skip
onLockConflict'drop' | 'force' | (threadId, message) => 'drop' | 'force'"drop"Behavior when a thread lock is already held. 'force' releases the existing lock and re-acquires it, enabling interrupt/steerability for long-running handlers

Accessing adapters

Use getAdapter to access platform-specific APIs when you need functionality beyond the unified interface:

lib/bot.ts
import type { SlackAdapter } from "@chat-adapter/slack";

const slack = bot.getAdapter("slack") as SlackAdapter;
await slack.setSuggestedPrompts(channelId, threadTs, [
  { title: "Get started", message: "What can you help me with?" },
]);

Webhook routing

The webhooks property provides type-safe handlers for each registered adapter. Wire these up to your HTTP framework's routes:

app/api/webhooks/slack/route.ts
import { bot } from "@/lib/bot";

export const POST = bot.webhooks.slack;
app/api/webhooks/teams/route.ts
import { bot } from "@/lib/bot";

export const POST = bot.webhooks.teams;

Lifecycle

The Chat instance initializes lazily on the first webhook. You can also initialize manually:

lib/bot.ts
await bot.initialize();

For graceful shutdown (e.g. in serverless teardown), call shutdown:

lib/bot.ts
await bot.shutdown();

Singleton pattern

Register a singleton when you need to access the Chat instance from multiple files:

lib/bot.ts
const bot = new Chat({ /* ...config */ }).registerSingleton();
export default bot;
lib/utils.ts
import { Chat } from "chat";

const bot = Chat.getSingleton();

Direct messaging

Open a DM thread with a user by passing their platform user ID or an Author object:

lib/bot.ts
const dm = await bot.openDM("slack:U123ABC");
await dm.post("Hey! Just wanted to follow up on your request.");

Channel access

Get a channel directly by its ID:

lib/bot.ts
const channel = bot.channel("slack:C123ABC");
await channel.post("Announcement: deploy complete!");