{"post":{"slug":"how-to-build-a-slack-app-2026","title":"How to build a Slack app in 2026","excerpt":"Slack apps in 2026 use Bolt, socket mode for dev, and event subscriptions for production. This guide gets you from zero to a working slash command in under an hour.","category":"code","date":"March 28, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">S</span>lack apps in 2026 are event-driven, Block Kit–composed, and almost always built with Bolt — Slack's official framework. The combination of Bolt's middleware model and Block Kit's interactive components covers everything from a simple slash command to a full workflow automation tool. This guide focuses on the JavaScript path (Node.js 20+), with notes on the Python equivalent.\n\n## What changed in 2026\n\n- **Bolt for JavaScript v4** ships as a first-class ESM package targeting Node.js 20+.\n- **Slack Platform (Deno Functions)** is an alternative for simple automations, but Bolt on Node remains the most capable path for complex apps.\n- **Workflow Builder integration** — apps can now expose \"functions\" that Slack Workflow Builder picks up without writing Workflow-Step APIs from scratch.\n- **Granular scopes matter.** Slack's App Directory reviews scopes carefully; requesting `channels:history` for a bot that doesn't need it will delay approval.\n\n## Project setup\n\n```bash\nmkdir my-slack-app && cd my-slack-app\nnpm init -y\nnpm install @slack/bolt\n```\n\nCreate `app.mjs`:\n\n```js\nimport { App } from '@slack/bolt';\n\nconst app = new App({\n  token: process.env.SLACK_BOT_TOKEN,\n  signingSecret: process.env.SLACK_SIGNING_SECRET,\n  socketMode: true, // dev only\n  appToken: process.env.SLACK_APP_TOKEN, // for socket mode\n});\n\napp.command('/ping', async ({ command, ack, respond }) => {\n  await ack();\n  await respond(`Pong, <@${command.user_id}>!`);\n});\n\nawait app.start();\nconsole.log('Bolt app is running!');\n```\n\nFor Socket Mode you need an **App-Level Token** (`xapp-…`) with `connections:write` scope, created in your app's \"Basic Information\" page.\n\n## Listening to events\n\n```js\napp.event('message', async ({ event, say }) => {\n  if (event.subtype) return; // ignore edits, deletes, etc.\n  if (event.text?.toLowerCase().includes('hello')) {\n    await say({ text: `Hey there, <@${event.user}>!` });\n  }\n});\n```\n\nSubscribe to events in your app manifest under **Event Subscriptions**. Add `message.channels` to listen in public channels (requires `channels:history` scope).\n\n## Slash commands + modals\n\n```js\napp.command('/feedback', async ({ command, ack, client }) => {\n  await ack();\n  await client.views.open({\n    trigger_id: command.trigger_id,\n    view: {\n      type: 'modal',\n      callback_id: 'feedback_modal',\n      title: { type: 'plain_text', text: 'Give feedback' },\n      submit: { type: 'plain_text', text: 'Submit' },\n      blocks: [\n        {\n          type: 'input',\n          block_id: 'feedback_block',\n          element: { type: 'plain_text_input', action_id: 'feedback_input', multiline: true },\n          label: { type: 'plain_text', text: 'Your feedback' },\n        },\n      ],\n    },\n  });\n});\n\napp.view('feedback_modal', async ({ view, ack, say }) => {\n  await ack();\n  const text = view.state.values.feedback_block.feedback_input.value;\n  console.log('Feedback received:', text);\n});\n```\n\n## Deployment comparison\n\n| Mode | Use case | Requires public URL |\n|---|---|---|\n| Socket Mode | Local dev, internal tools | No |\n| HTTP (Express) | Production, public apps | Yes |\n| Vercel / AWS Lambda | Serverless, low traffic | Yes |\n| Slack Platform (Deno) | Simple automations | No (Slack-hosted) |\n\nFor production on a VPS, switch `socketMode: false` and add an Express listener:\n\n```js\nconst app = new App({ token, signingSecret });\nconst { receiver } = app;\n// app is an Express-compatible receiver by default\nawait app.start(process.env.PORT ?? 3000);\n```\n\n## How to start\n\n1. Create an app at [api.slack.com/apps](https://api.slack.com/apps) → \"From scratch.\"\n2. Under \"OAuth & Permissions,\" add bot token scopes (`chat:write`, `commands`, etc.).\n3. Install the app to your workspace; copy `SLACK_BOT_TOKEN` and `SLACK_SIGNING_SECRET`.\n4. Enable Socket Mode, create an App-Level Token, copy `SLACK_APP_TOKEN`.\n5. Run locally, test slash commands in your workspace.\n\n## Common mistakes\n\n**Not calling `ack()` within 3 seconds.** Slack retries if it doesn't get an acknowledgement. Always `await ack()` immediately; do async work after.\n\n**Registering slash commands with a leading `/` in the app config.** The command name is `ping`, not `/ping`. Bolt adds the slash.\n\n**Forgetting `message.subtype` guards.** Message events fire for edits and deletions too. Filter `event.subtype` to avoid infinite loops or double-processing.\n\n**Using `say` outside a message event.** `say` posts to the originating channel. Outside message events, use `client.chat.postMessage` with an explicit `channel` ID.\n\n## What to skip\n\n- **DIY Slack event verification.** Bolt handles signature verification; don't replicate it.\n- **Polling Slack channels.** The Events API is push-based and far more efficient.\n- **Requesting all scopes \"just in case\"** — it fails App Directory review and is a security risk.\n\n## FAQ\n\n**Can I use Bolt with TypeScript?**\nYes — `@slack/bolt` ships full types. Use `AppOptions`, `SlashCommand`, and typed view/action payloads from the `@slack/types` package.\n\n**How do I handle multi-workspace (public Slack app) OAuth?**\nUse Bolt's built-in `OAuthInstallationStore`. Implement `storeInstallation` and `fetchInstallation` backed by your DB, then set `installerOptions`.\n\n**What is the difference between a bot token and a user token?**\nBot tokens (`xoxb-`) act as the bot user. User tokens (`xoxp-`) act on behalf of a human user. Most apps only need a bot token.\n\n**Can Slack apps run serverless?**\nYes, but each request is independent — don't rely on in-memory state. Use Redis or a DB for state. Bolt's HTTP mode works on Lambda and Vercel.\n\n## Where to go next\n\n- [How to build a Discord bot in 2026](/blog/how-to-build-a-discord-bot-2026)\n- [How to build a Telegram bot in 2026](/blog/how-to-build-a-telegram-bot-2026)\n- [How to add authentication to an app in 2026](/blog/how-to-add-authentication-to-an-app-2026)","hue":307,"metaTitle":"How to Build a Slack App in 2026 (Bolt + Block Kit)","metaDescription":"Build a Slack app in 2026 with Bolt for JavaScript. Covers slash commands, event subscriptions, modals, Block Kit, Socket Mode, and production deployment.","keywords":["how to build a slack app 2026","slack bolt tutorial 2026","slack slash commands 2026","slack block kit","slack event subscriptions","slack socket mode","slack bot node.js 2026","slack app deployment 2026","slack oauth 2026","slack modal forms"],"tldr":["**Use Bolt for JavaScript/Python** — it handles OAuth, event routing, and middleware; building on raw HTTP is unnecessary complexity.","**Socket Mode for development, HTTP for production** — no public URL needed locally; flip to HTTP + a reverse proxy in prod.","**Block Kit is the UI layer** — compose rich messages with buttons, modals, and home tabs using the Block Kit builder.","**Store the OAuth token securely** — for single-workspace apps use a `SLACK_BOT_TOKEN`; for multi-workspace use the OAuth installer with a token store.","**Skip:** building directly on top of the Slack Web API without Bolt — you will re-implement retry logic, signature verification, and middleware from scratch."],"readTime":"4 min read","wordCount":816},"related":[{"slug":"how-to-build-a-discord-bot-2026","title":"How to build a Discord bot in 2026","excerpt":"Discord bots in 2026 use slash commands, interactions, and gateway intents. This guide covers a production-ready setup with discord.js v15 in under an hour.","category":"code","date":"February 22, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":305},{"slug":"how-to-build-a-rest-api-in-node-2026","title":"How to build a REST API in Node in 2026: the complete guide","excerpt":"Building a production-ready REST API in Node.js in 2026 means choosing the right framework, structuring routes cleanly, and shipping validation and auth from day one.","category":"code","date":"March 11, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":318},{"slug":"how-to-build-a-telegram-bot-2026","title":"How to build a Telegram bot in 2026","excerpt":"Telegram bots use the Bot API over webhooks or long-polling. This guide covers a production-ready setup with grammY in 2026, including commands and middleware.","category":"code","date":"March 11, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":306}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"how-to-build-a-skincare-routine-2026","title":"How to build a skincare routine in 2026: the minimal effective approach","excerpt":"A five-product drugstore routine beats a twenty-step expensive one when you get the order and actives right. Here is the 2026 framework for every skin type.","category":"guides","date":"March 28, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":270},"older":{"slug":"how-to-build-a-website-2026","title":"How to build a website in 2026: from zero to live in a weekend","excerpt":"Building a website in 2026 is faster than ever, but the options are more confusing. This guide picks the right path for your goal and skill level.","category":"code","date":"March 28, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":306}}