slackblocks

September 17, 2026 · View on GitHub

Licence: MIT Licence: BSD-3-Clause Python Versions PyPI npm Go Maven Central NuGet Downloads Python CI TypeScript CI Go CI Java CI .NET CI Docs

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?

  • ConciseSectionBlock("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.typed in 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 Message straight into client.chat_postMessage(**message) with slack-sdk, pass a payload directly to @slack/web-api, pass Go block builders directly to slack-go/slack, pass Java blocks directly to the official Slack Java SDK, or serialize C# values with System.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.

The build notification rendered in Slack

Documentation

Repository layout

  • python/ — the established Python package (slackblocks on PyPI).
  • typescript/ — the TypeScript package (@nicklambourne/slackblocks on npm).
  • go/ — the Go v2 module (github.com/nicklambourne/slackblocks/go/v2).
  • java/ — the Java artifact (io.github.nicklambourne:slackblocks on Maven Central).
  • csharp/ — the .NET package (Slackblocks on 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.