Build Slack messages in TypeScript — without writing JSON by hand.
slackblocks is a typed, validating TypeScript wrapper around the Slack
Block Kit API. It exists because Block Kit JSON is
verbose, easy to get subtly wrong, and unpleasant to maintain in source control.
This release conforms to the shared cross-language slackblocks specification.
- Concise —
sectionBlock({ text: "Hello, *world*!" })instead of a 10-line JSON object. - Validated — character limits, required fields, mutually-exclusive options, and
element-type restrictions are enforced at construction time, with a typed error
hierarchy (
LengthError,MissingRequiredError, …), so you find out before hitting Slack's API. - Typed — strict factory inputs reject typo'd and excess properties at compile time; what you get back is the plain Slack-shaped object, ready for the wire.
- Drop-in compatible with the official
@slack/web-apiand Bolt — pass amessage(...)payload straight toclient.chat.postMessage(payload). - The same library in two languages — the Python
slackblocksshares the blocks, the validation rules, and the version number; a shared conformance corpus keeps both emitting the same Slack JSON. - Self-contained — a single ESM module with no runtime imports.
npm install @nicklambourne/slackblocksRequires Node 20.19+ or 22.12+. The package ships as ESM; on these Node versions
CommonJS consumers can require() it directly.
import {
actionsBlock,
button,
dividerBlock,
headerBlock,
message,
sectionBlock,
} from "@nicklambourne/slackblocks";
const payload = message({
channel: "#general",
text: "Build #482 passed", // plain-text fallback for notifications
blocks: [
headerBlock({ text: "Build #482 passed :white_check_mark:" }),
sectionBlock({
fields: ["*Branch*\n`main`", "*Author*\n@nick", "*Duration*\n3m 12s", "*Tests*\n1,247 passed"],
}),
dividerBlock(),
actionsBlock({
elements: [
button({ text: "View build", actionId: "view", url: "https://ci.example.com/482" }),
button({ text: "Re-run", actionId: "rerun", value: "482", style: "primary" }),
],
}),
],
});payload can be sent in one line with the official Slack SDK:
import { WebClient } from "@slack/web-api";
const client = new WebClient(process.env.SLACK_API_TOKEN);
await client.chat.postMessage(payload);Factory inputs use idiomatic camelCase and return plain Slack-shaped objects with
snake_case keys. Factories validate eagerly; pass { validate: false } as the final
argument for Slack features that have moved ahead of this package's limits registry.
- Full docs: https://nicklambourne.github.io/slackblocks/
- Installation
- Using Blocks — every block type with code in both languages, the JSON it produces, and screenshots.
- Sending Messages
- Cookbook — end-to-end recipes for build notifications, approval requests, modals, and more.
- TypeScript API Reference
- Troubleshooting & FAQ
- Changelog
slackblocks is dual-licensed under
MIT and
BSD-3-Clause.
Use whichever fits your project — this makes it safe to vendor into projects under
either license.
Contributions are welcome. The package lives in the typescript/ directory of the
slackblocks monorepo and uses
pnpm:
git clone https://github.com/nicklambourne/slackblocks.git
cd slackblocks
pnpm install
pnpm --filter @nicklambourne/slackblocks testFor the full development guide — testing conventions, the conformance-fixture workflow, and the release process — see the Contributing page.
Bug reports and feature requests: https://github.com/nicklambourne/slackblocks/issues.

