0
# Core Application
1
2
The App class is the central component of Slack Bolt, providing event-driven architecture for building Slack applications with comprehensive listener registration, middleware support, and lifecycle management.
3
4
## Capabilities
5
6
### App Constructor
7
8
Creates a new Slack Bolt application instance with configuration options.
9
10
```typescript { .api }
11
/**
12
* Creates a new Slack Bolt application instance
13
* @param options - Configuration options for the app
14
*/
15
constructor(options?: AppOptions);
16
17
interface AppOptions {
18
/** Bot token starting with xoxb- */
19
token?: string;
20
/** App-level token starting with xapp- (required for Socket Mode) */
21
appToken?: string;
22
/** Signing secret for request verification */
23
signingSecret?: string;
24
/** Custom receiver for handling HTTP requests */
25
receiver?: Receiver;
26
/** Custom authorization function */
27
authorize?: Authorize;
28
/** Custom logger instance */
29
logger?: Logger;
30
/** Log level for built-in logger */
31
logLevel?: LogLevel;
32
/** Ignore events from the bot itself */
33
ignoreSelf?: boolean;
34
/** Web API client options */
35
clientOptions?: WebClientOptions;
36
/** Conversation state store */
37
convoStore?: ConversationStore;
38
/** Enable Socket Mode connection */
39
socketMode?: boolean;
40
}
41
```
42
43
**Usage Example:**
44
45
```typescript
46
import { App } from "@slack/bolt";
47
48
const app = new App({
49
token: process.env.SLACK_BOT_TOKEN,
50
signingSecret: process.env.SLACK_SIGNING_SECRET,
51
socketMode: false, // Set to true for Socket Mode
52
logLevel: "INFO"
53
});
54
```
55
56
### Event Listeners
57
58
Register listeners for Slack events with optional event type filtering.
59
60
```typescript { .api }
61
/**
62
* Register listeners for Slack events
63
* @param eventType - Event type pattern to match
64
* @param listeners - Middleware functions to handle the event
65
*/
66
event<EventType extends string>(
67
eventType: EventType,
68
...listeners: Middleware<SlackEventMiddlewareArgs<EventType>>[]
69
): void;
70
```
71
72
**Usage Examples:**
73
74
```typescript
75
// Listen for app mentions
76
app.event("app_mention", async ({ event, say }) => {
77
await say(`Hello <@${event.user}>!`);
78
});
79
80
// Listen for when users join channels
81
app.event("member_joined_channel", async ({ event, client, logger }) => {
82
logger.info(`User ${event.user} joined channel ${event.channel}`);
83
});
84
85
// Listen for file shared events
86
app.event("file_shared", async ({ event, client }) => {
87
// Handle file shared event
88
});
89
```
90
91
### Message Listeners
92
93
Register listeners for message events with optional pattern matching.
94
95
```typescript { .api }
96
/**
97
* Register listeners for message events with optional pattern matching
98
* @param pattern - Text pattern to match (string or RegExp), optional
99
* @param listeners - Middleware functions to handle the message
100
*/
101
message(
102
pattern?: string | RegExp,
103
...listeners: Middleware<SlackEventMiddlewareArgs<'message'>>[]
104
): void;
105
```
106
107
**Usage Examples:**
108
109
```typescript
110
// Listen for all messages
111
app.message(async ({ message, say }) => {
112
if (message.subtype === undefined) {
113
await say("I heard you!");
114
}
115
});
116
117
// Listen for messages containing "hello"
118
app.message("hello", async ({ message, say }) => {
119
await say(`Hey there <@${message.user}>!`);
120
});
121
122
// Listen for messages matching a pattern
123
app.message(/^ticket-(\d+)/, async ({ message, say, context }) => {
124
const ticketId = context.matches[1];
125
await say(`Looking up ticket ${ticketId}...`);
126
});
127
```
128
129
### Action Listeners
130
131
Register listeners for interactive component actions (buttons, select menus, etc.).
132
133
```typescript { .api }
134
/**
135
* Register listeners for interactive component actions
136
* @param actionId - Action ID or constraint object to match
137
* @param listeners - Middleware functions to handle the action
138
*/
139
action<ActionId extends string>(
140
actionId: ActionId | ActionConstraints,
141
...listeners: Middleware<SlackActionMiddlewareArgs>[]
142
): void;
143
```
144
145
**Usage Examples:**
146
147
```typescript
148
// Listen for button clicks
149
app.action("button_click", async ({ body, ack, say }) => {
150
await ack();
151
await say(`<@${body.user.id}> clicked the button`);
152
});
153
154
// Listen for select menu selections
155
app.action("static_select-action", async ({ body, ack, client }) => {
156
await ack();
157
// Handle select menu selection
158
});
159
160
// Listen for overflow menu actions
161
app.action("overflow_menu_action", async ({ action, ack, respond }) => {
162
await ack();
163
await respond(`You selected: ${action.selected_option.value}`);
164
});
165
```
166
167
### Command Listeners
168
169
Register listeners for slash commands.
170
171
```typescript { .api }
172
/**
173
* Register listeners for slash commands
174
* @param commandName - Slash command name (e.g., "/hello")
175
* @param listeners - Middleware functions to handle the command
176
*/
177
command(
178
commandName: string,
179
...listeners: Middleware<SlackCommandMiddlewareArgs>[]
180
): void;
181
```
182
183
**Usage Examples:**
184
185
```typescript
186
// Handle /hello command
187
app.command("/hello", async ({ command, ack, respond }) => {
188
await ack();
189
await respond(`Hey there <@${command.user_id}>!`);
190
});
191
192
// Handle /ticket command with parameters
193
app.command("/ticket", async ({ command, ack, client, respond }) => {
194
await ack();
195
196
const args = command.text.split(" ");
197
const action = args[0];
198
199
if (action === "create") {
200
await respond("Creating a new ticket...");
201
} else if (action === "list") {
202
await respond("Listing your tickets...");
203
} else {
204
await respond("Usage: /ticket create|list");
205
}
206
});
207
```
208
209
### Shortcut Listeners
210
211
Register listeners for shortcuts (global and message shortcuts).
212
213
```typescript { .api }
214
/**
215
* Register listeners for shortcuts
216
* @param callbackId - Shortcut callback ID to match
217
* @param listeners - Middleware functions to handle the shortcut
218
*/
219
shortcut<CallbackId extends string>(
220
callbackId: CallbackId | ShortcutConstraints,
221
...listeners: Middleware<SlackShortcutMiddlewareArgs>[]
222
): void;
223
```
224
225
**Usage Examples:**
226
227
```typescript
228
// Handle global shortcut
229
app.shortcut("open_modal", async ({ shortcut, ack, client, body }) => {
230
await ack();
231
232
await client.views.open({
233
trigger_id: body.trigger_id,
234
view: {
235
type: "modal",
236
callback_id: "my_modal",
237
title: { type: "plain_text", text: "My App" },
238
close: { type: "plain_text", text: "Cancel" },
239
blocks: [
240
// Modal blocks here
241
]
242
}
243
});
244
});
245
246
// Handle message shortcut
247
app.shortcut("share_message", async ({ shortcut, ack, client }) => {
248
await ack();
249
// Handle sharing the message
250
});
251
```
252
253
### View Listeners
254
255
Register listeners for modal view submissions and closures.
256
257
```typescript { .api }
258
/**
259
* Register listeners for view submissions and closures
260
* @param callbackId - View callback ID to match
261
* @param listeners - Middleware functions to handle the view action
262
*/
263
view<CallbackId extends string>(
264
callbackId: CallbackId | ViewConstraints,
265
...listeners: Middleware<SlackViewMiddlewareArgs>[]
266
): void;
267
```
268
269
**Usage Examples:**
270
271
```typescript
272
// Handle modal submission
273
app.view("modal_callback", async ({ ack, body, view, client }) => {
274
await ack();
275
276
const values = view.state.values;
277
const user = body.user.id;
278
279
// Process form data
280
});
281
282
// Handle modal closure
283
app.view({ callback_id: "modal_callback", type: "view_closed" },
284
async ({ ack, body, view }) => {
285
await ack();
286
// Handle modal being closed
287
}
288
);
289
```
290
291
### Global Middleware
292
293
Add middleware that runs for all incoming requests.
294
295
```typescript { .api }
296
/**
297
* Add global middleware that runs for all requests
298
* @param middlewares - Middleware functions to add
299
*/
300
use(...middlewares: Middleware<AnyMiddlewareArgs>[]): void;
301
```
302
303
**Usage Examples:**
304
305
```typescript
306
// Add custom logging middleware
307
app.use(async ({ logger, body, next }) => {
308
logger.info("Incoming request", body);
309
await next();
310
});
311
312
// Add authorization middleware
313
app.use(async ({ context, client, next }) => {
314
// Add custom context properties
315
context.customData = await loadUserData(context.userId);
316
await next();
317
});
318
319
// Add built-in middleware
320
import { ignoreSelf } from "@slack/bolt";
321
app.use(ignoreSelf);
322
```
323
324
### Error Handling
325
326
Register global error handler for unhandled errors.
327
328
```typescript { .api }
329
/**
330
* Register global error handler
331
* @param errorHandler - Function to handle errors
332
*/
333
error(errorHandler: (error: CodedError) => Promise<void>): void;
334
```
335
336
**Usage Example:**
337
338
```typescript
339
app.error(async (error) => {
340
console.error("An error occurred:", error);
341
342
// Send error to monitoring service
343
if (error.code === "slack_bolt_authorization_error") {
344
// Handle authorization errors
345
}
346
});
347
```
348
349
### Application Lifecycle
350
351
Start and stop the Slack application.
352
353
```typescript { .api }
354
/**
355
* Start the Slack application
356
* @param port - Port number for HTTP server (optional)
357
* @returns Promise that resolves when the app starts
358
*/
359
start(port?: number): Promise<unknown>;
360
361
/**
362
* Stop the Slack application
363
* @returns Promise that resolves when the app stops
364
*/
365
stop(): Promise<unknown>;
366
```
367
368
**Usage Examples:**
369
370
```typescript
371
// Start the app
372
(async () => {
373
await app.start(3000);
374
console.log("⚡️ Bolt app is running on port 3000!");
375
})();
376
377
// Graceful shutdown
378
process.on("SIGINT", async () => {
379
await app.stop();
380
process.exit(0);
381
});
382
```
383
384
### Options and Function Listeners
385
386
Register listeners for select menu options and custom functions.
387
388
```typescript { .api }
389
/**
390
* Register listeners for external select menu options
391
* @param actionId - Action ID or constraints to match
392
* @param listeners - Middleware functions to handle options request
393
*/
394
options<ActionId extends string>(
395
actionId: ActionId | OptionsConstraints,
396
...listeners: Middleware<SlackOptionsMiddlewareArgs>[]
397
): void;
398
399
/**
400
* Register listeners for custom functions
401
* @param callbackId - Function callback ID to match
402
* @param listeners - Middleware functions to handle function execution
403
*/
404
function<CallbackId extends string>(
405
callbackId: CallbackId,
406
...listeners: Middleware<SlackCustomFunctionMiddlewareArgs>[]
407
): void;
408
```
409
410
**Usage Examples:**
411
412
```typescript
413
// Handle external select menu options
414
app.options("external_select", async ({ options, ack }) => {
415
await ack({
416
options: [
417
{ text: { type: "plain_text", text: "Option 1" }, value: "opt1" },
418
{ text: { type: "plain_text", text: "Option 2" }, value: "opt2" }
419
]
420
});
421
});
422
423
// Handle custom function execution
424
app.function("my_function", async ({ inputs, complete, fail }) => {
425
try {
426
const result = await processInputs(inputs);
427
await complete({ outputs: result });
428
} catch (error) {
429
await fail({ error: "Processing failed" });
430
}
431
});
432
```
433
434
## Authorization Types
435
436
```typescript { .api }
437
type Authorize = (
438
source: AuthorizeSourceData
439
) => Promise<AuthorizeResult>;
440
441
interface AuthorizeSourceData {
442
teamId: string;
443
enterpriseId?: string;
444
userId?: string;
445
conversationId?: string;
446
isEnterpriseInstall?: boolean;
447
}
448
449
interface AuthorizeResult {
450
botToken?: string;
451
userToken?: string;
452
botId?: string;
453
botUserId?: string;
454
userId?: string;
455
teamId?: string;
456
enterpriseId?: string;
457
}
458
```