slackblocks
September 17, 2026 · View on GitHub
Build Slack messages in Python, TypeScript, Go, Java, or C# — without writing JSON by hand.
Anyone who has built a non-trivial Slack message knows the drill: a wall of nested
Block Kit JSON, five levels deep, where a typo'd
field name or an over-long string sails silently through your code and only blows up
when Slack rejects the API call. slackblocks replaces that JSON with typed objects
that assemble it for you — and that complain at construction time, in your editor and
your tests, rather than in production.
Why slackblocks?
- Concise —
SectionBlock("Hello, *world*!")/SectionBlock.builder().markdownText("Hello, *world*!").build()/new SectionBlock(text: "Hello, *world*!")instead of a ten-line JSON object. - Validated up front — character limits, required fields, mutually-exclusive options, and element-type restrictions are enforced when you construct the block, so you find out before hitting Slack's API.
- Typed — full type hints and
py.typedin Python, strict types in TypeScript, compile-checked concrete fluent builders in Go and Java, and typed constructors with nullable annotations in C#. - Plays well with established Slack clients — unpack a
Messagestraight intoclient.chat_postMessage(**message)withslack-sdk, pass a payload directly to@slack/web-api, pass Go block builders directly toslack-go/slack, pass Java blocks directly to the official Slack Java SDK, or serialize C# values withSystem.Text.Json. - One library, five languages — the same blocks, validation rules, and version numbers in Python, TypeScript, Go, Java, and C#. A shared conformance corpus keeps all five implementations emitting the same Slack JSON.
- Everything Block Kit ships today — all current blocks and elements, rich text, modals and Home tabs, and the 2025 block families (tables, cards, carousels, charts).
- Light — zero runtime dependencies in Python, a self-contained ESM module on npm,
one direct Go dependency (
slack-go/slack), Java integration through the official Slack model interfaces, and no dependencies beyond .NET itself in C#.
Installation
Python (3.10+ — earlier Pythons should pin the 1.x line, see
Compatibility):
pip install slackblocks
TypeScript / JavaScript (Node 20.19+ or 22.12+, ESM):
npm install @nicklambourne/slackblocks
Go (1.22+):
go get github.com/nicklambourne/slackblocks/go/v2
Java (17+):
<dependency>
<groupId>io.github.nicklambourne</groupId>
<artifactId>slackblocks</artifactId>
<version>2.4.0</version>
</dependency>
C# (.NET 8+):
dotnet add package Slackblocks
Quickstart
A CI notification, in Python:
from slackblocks import (
ActionsBlock,
Button,
DividerBlock,
HeaderBlock,
Message,
SectionBlock,
)
message = Message(
channel="#general",
text="Build #482 passed", # plain-text fallback for notifications
blocks=[
HeaderBlock("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", action_id="view", url="https://ci.example.com/482"),
Button(text="Re-run", action_id="rerun", value="482", style="primary"),
],
),
],
)
Send it in one line with the official Slack SDK — the ** operator unpacks
Message objects directly into the call, no to_dict() boilerplate:
import os
from slack_sdk import WebClient
client = WebClient(token=os.environ["SLACK_API_TOKEN"])
client.chat_postMessage(**message)
The same message in TypeScript:
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"),
),
)
.build();
import { WebClient } from "@slack/web-api";
const client = new WebClient(process.env.SLACK_API_TOKEN);
await client.chat.postMessage(payload);
And in Go:
client := slack.New(os.Getenv("SLACK_API_TOKEN"))
_, _, err := client.PostMessageContext(
context.Background(),
"C0123456",
slack.MsgOptionText("Build #482 passed", false),
slack.MsgOptionBlocks(
slackblocks.NewHeaderBlock().Text("Build #482 passed :white_check_mark:"),
slackblocks.NewSectionBlock().Fields(
"*Branch*\n`main`",
"*Tests*\n1,247 passed",
),
slackblocks.NewDividerBlock(),
),
)
And in Java:
SectionBlock block = SectionBlock.builder()
.markdownText("Build #482 passed :white_check_mark:")
.build();
var client = Slack.getInstance().methods(System.getenv("SLACK_API_TOKEN"));
client.chatPostMessage(ChatPostMessageRequest.builder()
.channel("C0123456")
.text("Build #482 passed")
.blocks(List.of(block))
.build());
And in C#:
using Slackblocks.Blocks;
using Slackblocks.Elements;
using Slackblocks.Payloads;
var message = new MessagePayload(
"C0123456",
text: "Build #482 passed", // plain-text fallback for notifications
blocks:
[
new HeaderBlock("Build #482 passed :white_check_mark:"),
new SectionBlock(fields: ["*Branch*\n`main`", "*Tests*\n1,247 passed"]),
new DividerBlock(),
new ActionsBlock([new ButtonElement("View build", "view", url: "https://ci.example.com/482")]),
]);
// POST message.ToJson() to chat.postMessage with HttpClient and a bot token.
Documentation
- Full docs: https://nicklambourne.github.io/slackblocks/
- Installation
- Using Blocks — every block type with code in all five languages, the JSON it produces, and screenshots.
- Sending Messages
- Recipe Book — end-to-end recipes for build notifications, approval requests, modals, and more.
- API Reference — Python and TypeScript, and Go, and Java, and C#.
- Migrating from 1.x · Troubleshooting & FAQ
- Changelogs: Python · TypeScript · Go · Java · C#
- Roadmap — including the TypeScript legacy API removal planned for v3.0.
Repository layout
python/— the established Python package (slackblockson PyPI).typescript/— the TypeScript package (@nicklambourne/slackblockson npm).go/— the Go v2 module (github.com/nicklambourne/slackblocks/go/v2).java/— the Java artifact (io.github.nicklambourne:slackblockson Maven Central).csharp/— the .NET package (Slackblockson NuGet).spec/— the shared conformance contract: fixtures, invalid cases, limits, and capability coverage that all five implementations are tested against.docs/— the Docusaurus documentation site.
Licensing
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.
Contributing
Contributions are welcome. Python development uses uv from
python/; TypeScript and the docs site use pnpm from the repository
root:
git clone https://github.com/nicklambourne/slackblocks.git
cd slackblocks/python
uv sync --group dev
uv run pytest test/unit test/conformance test/docs
cd ..
pnpm install
pnpm --filter @nicklambourne/slackblocks test
cd go
go test -race -cover ./...
cd ../java
./mvnw clean verify
cd ../csharp
dotnet test
For the full development guide — testing conventions, the conformance-fixture workflow, docstring style, and the release process — see the Contributing page.
Bug reports and feature requests: https://github.com/nicklambourne/slackblocks/issues.