Slack App Framework for Cloudflare Workers
slack-cloudflare-workers is an opinionated framework for building Slack applications designed specifically for Cloudflare Workers, leveraging their serverless environment. Inspired by Slack's popular Bolt framework but not strictly following its blueprint, it distinguishes itself with a strong TypeScript focus, built-in lazy listener capabilities (similar to bolt-python), and a commitment to zero additional runtime dependencies beyond its foundational `slack-edge` module. The current stable version is 1.3.9. This library caters to developers seeking highly performant, type-safe, and lightweight Slack integrations on the Cloudflare Workers platform, providing a streamlined experience compared to general-purpose Node.js frameworks. While release cadence isn't explicitly stated, the active development and frequent updates to the `slack-edge` ecosystem suggest a responsive maintenance schedule.
Common errors
-
Error: Signature verification failed.
cause The Slack `x-slack-signature` header does not match the computed signature using `SLACK_SIGNING_SECRET`.fixEnsure `SLACK_SIGNING_SECRET` is correctly set in your Cloudflare Worker's environment variables and exactly matches the value from your Slack app settings. Check for leading/trailing whitespace or accidental character changes. -
TypeError: app.message is not a function
cause The `App` instance was not correctly initialized or the import path is wrong, leading to an undefined or incorrect object.fixVerify that `import { App } from 'slack-cloudflare-workers';` is correct and that `new App({ ... })` is called with valid parameters before attempting to call listener methods. -
Failed to execute 'fetch' on 'WorkerGlobalScope': The provided URL 'undefined' is not valid.
cause This error often occurs when `SLACK_BOT_TOKEN` is missing or undefined, causing the underlying `SlackAPIClient` to attempt an API call with an invalid base URL.fixEnsure `SLACK_BOT_TOKEN` is correctly provided to the `App` instance, either directly or via environment variables, and that it is a valid Slack bot token.
Warnings
- gotcha This framework's design, while inspired by Slack's Bolt.js, does not strictly follow its blueprint. Developers migrating from Bolt.js might find differences in API surface or expected behavior, requiring careful review of the `slack-cloudflare-workers` documentation.
- breaking Prior to version 1.0, the package's core logic and API surface were less stable. While no explicit breaking change documentation is provided for minor versions, it is generally recommended to pin to a major version (e.g., `slack-cloudflare-workers@^1.0.0`) and review changelogs for updates.
- gotcha Cloudflare Workers do not have a traditional filesystem or `process.env` in the same way as Node.js. Environment variables must be passed explicitly via the `env` argument in the `fetch` handler or configured via `wrangler.toml` and accessed via the `Env` interface. Hardcoding secrets is a security risk.
Install
-
npm install slack-cloudflare-workers -
yarn add slack-cloudflare-workers -
pnpm add slack-cloudflare-workers
Imports
- App
const App = require('slack-cloudflare-workers');import { App } from 'slack-cloudflare-workers'; - Context
import type { Context } from 'slack-cloudflare-workers'; - SlackAPIClient
import type { SlackAPIClient } from 'slack-cloudflare-workers';
Quickstart
import { App } from 'slack-cloudflare-workers';
interface Env {
SLACK_SIGNING_SECRET: string;
SLACK_BOT_TOKEN: string;
}
const app = new App({
signingSecret: process.env.SLACK_SIGNING_SECRET ?? 'your-signing-secret-if-not-env',
token: process.env.SLACK_BOT_TOKEN ?? 'your-bot-token-if-not-env',
});
// Listen for a 'hello' message
app.message('hello', async ({ say, payload }) => {
await say(`Hello, <@${payload.user}>! How can I help you?`);
});
// Respond to a slash command
app.command('/echo', async ({ command, ack, respond }) => {
await ack(); // Acknowledge the command immediately
await respond(`You said: ${command.text}`);
});
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
// Ensure the app instance uses the environment variables from the Worker's context
// This is crucial for local development vs. deployed Worker
app.oauth = undefined; // Reset OAuth for each request to use correct env
app.receiver.signingSecret = env.SLACK_SIGNING_SECRET;
app.client.token = env.SLACK_BOT_TOKEN;
return app.fetch(request, env, ctx);
},
};