# action-slack-notify posts a workflow message to Slack from a Go binary

> rtCamp's action-slack-notify is an MIT licensed GitHub Action that sends a message to a Slack channel through an incoming webhook, configured entirely through environment variables such as SLACK_CHANNEL, SLACK_MSG_AUTHOR and MSG_MINIMAL. The action runs from a Go binary in a container that also carries jq, shyaml and HashiCorp Vault.

**rtCamp/action-slack-notify** — GitHub Action for sending a notification to a Slack channel

- Repository: https://github.com/rtCamp/action-slack-notify
- Website: https://github.com/rtCamp/github-actions-library
- Stars: 1,188 · Forks: 253
- Language: Go
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/rtcamp-action-slack-notify

## The message is assembled for you, from the commit and the run

action-slack-notify is a GitHub Action to send a message to a Slack channel, and it is one of a family. This action is a part of the GitHub Actions Library created by rtCamp, and the README points at the library for the rest of the set.

The basic use is three steps. Create a .github/workflows/slack-notify.yml file, add the step, and create a SLACK_WEBHOOK secret.

```yml
on: push
name: Slack Notification Demo
jobs:
  slackNotification:
    name: Slack Notification
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Slack Notification
      uses: rtCamp/action-slack-notify@v2
      env:
        SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
```

The webhook token comes from Slack's incoming webhooks page, and the README says the action can be used after any other action, so it is a step you add at the end of a job rather than a workflow of its own.

The interesting part is what arrives in Slack. The environment variable table shows that the default message is Generated from git commit message, and the recommended advice is not to override it, which tells you the default is considered good. The other default values are the same idea, a username of rtBot, a footer reading Powered By rtCamp's GitHub Actions Library, and an author defaulting to $GITHUB_ACTOR, the person who triggered the action.

So a default run posts a message with the commit, the author, the ref, the event and a link to the run. The MSG_MINIMAL option then removes Ref, Event, Actions URL and Commit, and it accepts a comma separated whitelist instead of true, so MSG_MINIMAL: event keeps the event and drops the rest. That is a level of detail that suggests the action has been tuned against real workflows where a full message was noise and a single field was the point.

## Colours, mentions and avatars are all environment variables

The variable table is the actual user interface of the action, and it is worth reading as a design document.

SLACK_CHANNEL specifies the Slack channel the message is sent to, defaulting to the one set during webhook creation. SLACK_USERNAME sets the name the message posts under, and the README notes it does not need to be a real username. SLACK_ICON is a URL to an avatar image, and SLACK_ICON_EMOJI is the alternative, an emoji shortcode such as :bell: for when you do not want to host an image.

SLACK_COLOR is the most interesting, because it is a status indicator. It defaults to good, which is the green that Slack uses for a success message, and the README says you can pass ${{ job.status }} for automatic colouring, or an RGB value like #efefef which changes the colour of the left side vertical line of the Slack message. The other valid values are success, cancelled and failure.

So the same action can post a green message when a job passes and a red one when it fails, without the workflow author writing any conditional logic, and that is the kind of thing a workflow gets done with a single environment variable.

SLACK_LINK_NAMES, set to true, enables mention in the Slack message, which is how a workflow can notify a person by name rather than posting to a channel and hoping someone reads it.

The remaining four are the message body. SLACK_MESSAGE is the main text in the attachment, SLACK_TITLE is the title before it, SLACK_FOOTER is the footer, and SLACK_MSG_AUTHOR is the GitHub username of the person who triggered the action, which you can override when the trigger was not a person, a scheduled run or a push by a bot account.

And there is a link between this action and another in the same library. The Site and SSH Host details are only available if this action is run after the Deploy WordPress GitHub action, which tells you the two share a convention for passing context between steps, most likely through the environment that the earlier step writes.

## A Go binary, a shell entrypoint and a downloaded Vault

The repository is small, and the top level listing shows what the action actually is. There is main.go and main.sh and entrypoint.sh and action.yml, plus a Dockerfile, and nothing else of substance.

The Dockerfile is where the interesting decisions are, and it is a two stage build with a base image pinned by digest.

```dockerfile
FROM golang:1.23-alpine3.19@sha256:5f3336882ad15d10ac1b59fbaba7cb84c35d4623774198b36ae60edeba45fd84 AS builder

ENV CGO_ENABLED 0
ENV GOOS linux

RUN go build -a -installsuffix cgo -ldflags '-w  -extldflags "-static"' -o /go/bin/slack-notify main.go
```

CGO_ENABLED 0 with a static link and the extldflags for static means the binary has no libc dependency, which is what lets the runtime stage be a bare Alpine image.

The runtime stage is alpine, also pinned by digest, with the comment noting it is alpine:latest as of 2024-03-11. The action metadata is carried as OCI labels on the builder stage, with a bell icon, a yellow colour, the display name Slack Notify and the description This action will send notification to Slack.

Then the runtime dependencies, and they are more than a Slack poster needs. The image installs bash, jq, ca-certificates, python3, py3-pip and rsync, and then pip installs shyaml with the break-system-packages flag. It then downloads HashiCorp Vault.

```dockerfile
ENV VAULT_VERSION 1.0.2

RUN wget https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_amd64.zip && \
	unzip vault_${VAULT_VERSION}_linux_amd64.zip && \
	rm vault_${VAULT_VERSION}_linux_amd64.zip && \
	mv vault /usr/local/bin/vault
```

So the action image carries a Vault client, which is presumably how the library's other actions read secrets, and the version is pinned at 1.0.2 in the Dockerfile. The Vault binary is downloaded over the network during the image build, not copied from a base image, which is a supply chain consideration worth noting for a security conscious team, and it also means the runtime image is larger than the Go binary alone would suggest.

There is one more fix in the Dockerfile, and the comment links the underlying issue.

```dockerfile
# fix the missing dependency
RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
```

The symlink is there because some tool invoked in the entrypoint expects the glibc loader path, and Alpine uses musl, so the path does not exist. This is a compatibility shim for a binary in the image, and the linked Stack Overflow question is the reference.

## Where action-slack-notify is the wrong choice

The first wrong case is a workflow that needs data back from Slack. The action posts a message and that is the whole contract. There is no interactive component, no button handling, no approval flow, and no way to read a response into a later step. A workflow where a human approves a deployment by clicking something in Slack needs a different tool entirely.

The second wrong case is a team that already has a notification layer. Most organisations with a large GitHub footprint have a central chat integration, a bot, or a status dashboard, and adding an action that posts a bespoke message means your notifications come from two systems with different formats and different levels of detail. The value of this action is highest for a small team whose workflows are not yet centralised.

The third wrong case is a security review that objects to the image contents. The runtime image installs a HashiCorp Vault binary downloaded during the build and pip installs shyaml with break-system-packages, which bypasses the protection a modern Python environment manager gives you. For an action whose entire job is to post a message, that is a lot of surface, and a team with a strict image allowlist may prefer to write the thirty lines of curl themselves.

The fourth wrong case is a workflow that needs more than a message. The action has no data transformation, no conditional logic, no file upload. A workflow that wants to post a summary of a test run with the failure details extracted from the output is asking for something this action does not do.

## How it differs from posting to Slack with curl

The comparison worth making is with a raw call to the incoming webhook, because the action is ultimately doing that and the question is what it adds.

A curl command in a workflow step is four lines. You build a JSON payload with the text and the attachments, and you POST it to the webhook URL. That works, it has no dependencies, and it takes about two minutes to write.

What the action adds is the assembly. The default message is generated from the commit message and includes the ref, the event, a link to the run and the commit, and the author is the person who triggered the run. Writing that by hand in every workflow means every workflow author has to know the GitHub Actions context syntax for each of those fields, and getting it slightly wrong in one workflow is a broken message in one channel.

The second thing it adds is the standardisation of the shape. A workflow that sets SLACK_COLOR to ${{ job.status }} and gets a green or a red message, with an avatar emoji and a title, produces a channel where failures are visible at a glance. Four environment variables and every workflow in the repository looks the same.

The third thing is the MSG_MINIMAL option, and this is the detail that shows it has been used. A notification that includes everything is a notification nobody reads, so the option that removes the ref, the event, the actions URL and the commit, with the ability to whitelist one of them back, is a response to real feedback. A raw curl does not have that.

The fourth is the shared context with the rest of the library. The Site and SSH Host fields appearing only when the action runs after the Deploy WordPress action means the library has a convention for passing information between steps, so a chain of actions in the library composes, where a set of independent curl calls does not.

The trade is the one to be clear about. You are depending on a container image that carries a Go binary, a shell entrypoint, jq, Python, shyaml and a downloaded Vault, in exchange for not writing the message assembly. For a team already using the library, that is obviously right. For a team with one workflow, the curl is better.

## Conclusion

action-slack-notify fits a GitHub Actions workflow that wants a readable notification of what just happened, with the message contents assembled for you from the commit and the run, and it fits a team that has already standardised on the rtCamp actions library. It does not fit a workflow that needs structured data out of Slack, since the action only posts, and it does not fit an organisation whose policy forbids downloading a HashiCorp Vault binary during the image build. Before adopting it, note that the image fetches Vault 1.0.2 and pip installs shyaml with the break-system-packages flag, and that the current release is v2.4.0 from 2026-06-05 with the last push on 2026-08-13.

## FAQ

### How do I set up action-slack-notify in a workflow?

Create a .github/workflows/slack-notify.yml file, add a step using rtCamp/action-slack-notify@v2 with the SLACK_WEBHOOK environment variable set from secrets.SLACK_WEBHOOK, and create that secret in the repository settings. The webhook token itself comes from Slack's incoming webhooks page.

### Which environment variables does action-slack-notify support?

SLACK_CHANNEL, SLACK_USERNAME defaulting to rtBot, SLACK_MSG_AUTHOR defaulting to $GITHUB_ACTOR, SLACK_ICON, SLACK_ICON_EMOJI, SLACK_COLOR defaulting to good, SLACK_LINK_NAMES, SLACK_MESSAGE generated from the git commit message, SLACK_TITLE, SLACK_FOOTER, and MSG_MINIMAL which removes the Ref, Event, Actions URL and Commit fields or whitelists a comma separated subset of them.

### Can action-slack-notify colour the message by job status?

Yes. SLACK_COLOR accepts ${{ job.status }} for automatic colouring, and the other valid values are success, cancelled and failure, with good as the default. An RGB value like #efefef can also be passed to change the colour of the left side vertical line of the Slack message.

### What is in the action-slack-notify container image?

A statically linked Go binary built with CGO_ENABLED 0, on an Alpine base pinned by digest, with bash, jq, ca-certificates, python3, py3-pip and rsync installed, shyaml pip installed, and HashiCorp Vault 1.0.2 downloaded during the build. The entrypoint is entrypoint.sh.

### What license is action-slack-notify released under?

MIT, with a LICENSE file at the root of the repository. It is part of the rtCamp GitHub Actions Library, and the current release is v2.4.0 from 2026-06-05 with the last push to master on 2026-08-13.

## Sources

- [License: MIT](https://github.com/rtCamp/action-slack-notify/blob/master/LICENSE)
- [Project website](https://github.com/rtCamp/github-actions-library)
- [README](https://github.com/rtCamp/action-slack-notify/blob/master/README.md)
- [Releases](https://github.com/rtCamp/action-slack-notify/releases)
- [rtCamp/action-slack-notify on GitHub](https://github.com/rtCamp/action-slack-notify)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rtcamp-action-slack-notify
