Use the new Slack CLI to create and deploy Slack apps. With the Slack CLI, developers can create an app and generate some boilerplate code in seconds.
This section walks through setting up your environment for next gen platform development.
We've built a command line interface to make the process of creating new apps, running them, and deploying them easier. Binaries are available for macOS and Windows.
Deno is currently a pre-requisite for using the CLI — if you do not have Deno installed, please do so first.
Additionally, the experience of writing an app will be greatly enhanced if your IDE includes support for Deno. Here's a plugin to add Deno capabilities to VS Code.
To install the Slack CLI:
slack
binary to a destination in your path (we recommend /usr/local/bin
). For Windows, copy the .exe
file into any location accessible in your path.slack version
and verifying the version matches the one you downloaded.Now you can now use the Slack CLI to authenticate and create a new app.
Before you can create an app, you must authenticate.
Run slack login
— this will display some instruction text and a string to copy and paste in any channel in the test workspace.
/slackauthticket ABC123DEF...XYZ
Copy the entire string, including the leading /
, and paste it into any channel in your Slack workspace. (You are essentially calling a special slash command that will authenticate your app with Slack).
Run slack auth info
for details on your active workspace authorization.
Now that you've authenticated, you can create a new app.
Now you can create an app! cd
to a directory where you have write access and want your app to live, most likely in your home. Then, run
$ slack create [optional-project-name]
This will create a new project called with a random name like priceless-lemur-123
.
If you want to name your project something specific, include an additional parameter
$ slack create my-new-project
Once the app has finished running, you'll have a new directory that contains a skeleton app.
$ cd my-new-project
The structure of these next-generation apps aims to favor convention over configuration. Directories are named logically and the files within those directories map to specific functionality with an app. For example, the functions
directory contains a list of an app's functions, with a single file for each function an app defines.
This section walks you through how your app is structured and how the different pieces tie together.
We will then make a sample function that takes in a string input and returns a capitalized version.
Your new project has a directory structure that should resemble the following:
.slack/
- apps.json
- cli.json
assets/
- icon.png
functions/
- myfunction.ts
tables/
- mytable.ts
triggers/
- mytrigger.ts
workflows/
- myworkflow.ts
import_map.json
project.ts
README.md
Functions: Modular, reusable, atomic blocks of functionality that can be grouped together as workflows. A function defines inputs, performs some useful bit of work using those inputs, and responds with pre-defined outputs. You'll be able to quickly write custom functions, deploy them via the CLI, and building workflows using these functions. Check out our functions documentation to learn more.
Workflows: A workflow is a group of functions, including built-in functions provided by Slack. Check out our workflows documentation to learn more.
Triggers: Define how workflows are called, such as a message action, shortcut, or event, where it is able to be executed, and who can execute it. Check out our triggers documentation to learn more.
Tables: Define tables and store data to power your application. Check out our tables documentation to learn more.
Project.ts: Contains all of the metadata about a project, such as the name of project, description, and requested OAuth scopes. It also contains a list of defined triggers and tables.
A function is defined via the DefineFunction
method, which is part of the SDK that gets included with every newly created project. The function is exported so that it can be used elsewhere in your app (such as workflows). DefineFunction
accepts a name (as a string) and object that defines the input and output parameters as well as an anonymous, asynchronous function that performs that actual work of the function (i.e. taking the input, doing something like calling an API, and then providing an output via a promise).
Let's create a function that will take as input a string and an interger and return a string with the value of the remaining budget after expenses:
budget.ts
file under the functions/
directory of your project.import { DefineFunction, Schema } from "slack-cloud-sdk/mod.ts";
export const RemainingBudget = DefineFunction(
"budget",
{
title: "Budget Calculator",
description: "Calculates your remaining budget",
input_parameters: {
required: [],
properties: {
budget: {
type: Schema.types.integer,
description: "The provided budget",
},
expenses: {
type: Schema.types.string,
description: "The provided expenses",
}
}
},
output_parameters: {
required: [],
properties: {
remainder: {
type: Schema.types.string,
description: "The remaining budget",
},
}
},
},
async ({ inputs, env }) => {
console.log(`calculating ${inputs.budget}.`);
console.log(`SLACK_API_URL=${env["SLACK_API_URL"]}`);
const remainder = String(
inputs.budget -
(inputs.expenses.split(",").map(Number)
.reduce(
(a, b) => a + b,
0,
)),
);
return await {
outputs: { remainder },
};
},
);
Now that we have defined our RemainingBudget
, we need to connect it to Workflow
.
Let's create a workflow that leverages our RemainingBudget
, take its output and uses a built-in Slack function to post it to a channel:
calc_budget.ts
file under the workflows/
directory of your project.import { DefineWorkflow, Schema } from "slack-cloud-sdk/mod.ts";
import { RemainingBudget } from "../functions/budget.ts";
export const CalculateBudgetRemainder = DefineWorkflow("calculate_budget", {
title: "Calculate Remaining Budget",
description: "Calculates your remaining budget from a provided number.",
input_parameters: {
required: [],
properties: {
budget: {
type: Schema.types.integer,
description: "What's your total budget?",
},
expenses: {
type: Schema.types.string,
description: "List your expenses, separated by commas",
},
channel: {
type: Schema.slack.types.channel_id,
description: "Channel to send remaining budget",
}
}
},
});
const step1 = CalculateBudgetRemainder.addStep(RemainingBudget, {
budget: CalculateBudgetRemainder.inputs.budget,
expenses: CalculateBudgetRemainder.inputs.expenses,
});
CalculateBudgetRemainder.addStep(Schema.slack.functions.SendMessage, {
channel_id: CalculateBudgetRemainder.inputs.channel,
message:
`You have *$${step1.outputs.remainder}* remaining from your budget of *$${CalculateBudgetRemainder.inputs.budget}*`,
});
Now that we have defined our CalculateBudgetRemainder
workflow, we need to connect it to Trigger
. There are many different kinds of triggers, but for our purposes we will use a Shortcut trigger. This Shortcut will be how users in your Slack workspace will interact with this app.
Let's create a trigger that leverages our CalculateBudgetRemainder
workflow, take its output and uses a built-in Slack function to post it to a channel:
budget_shortcut.ts
file under the triggers/
directory of your project.import { DefineTrigger, TriggerTypes } from "slack-cloud-sdk/mod.ts";
import { CalculateBudgetRemainder } from "../workflows/calc_budget.ts";
export const BudgetShortcut = DefineTrigger("calc_budget_shortcut", {
type: TriggerTypes.Shortcut,
name: "calculate",
description: "Calculates your remaining budget",
})
.runs(CalculateBudgetRemainder)
.withInputs((ctx) => ({
channel: ctx.data.channel_id,
}));
project.ts
in the project root:
Import your new trigger at the top of your project.ts
file:
import { BudgetShortcut } from "./triggers/budget_shortcut.ts";
Make sure BudgetShortcut
is referenced in the triggers
array of your Project
definition, so the relevant section of your project.ts
file looks like the following:
triggers: [BudgetShortcut],
This section walks you through how to navigate app deployment when Admin Approved Apps is enabled on a workspace.
When this setting is enabled on a workspace, apps will need to be approved by a workspace administrator before it can be deployed.
If Admin Approved Apps is enabled on your workspace you will be notified upon deployment. Run the slack deploy
command to begin the deployment process:
slack deploy
You will see a message like this on your command line:
Admin Approval is required on this workspace.
? Would you like to send a request to the workspace admin for approval to install this app? (y/N)
Reply with y
to send a request to your workspace admin. You will be asked to submit a reason for the request. Admins will receive a Slackbot message:
If your app is approved you will get a message from Slackbot on your Workspace letting you know. You will then be able to re-deploy your app.
If the admin clicks on the Restrict for Workspace
button it means your app has was denied. You will get a DM from Slackbot letting you know. Any attempt to re-deploy the app will result in the following error:
Error: failed to add app: failed to create an app manifest: failed to install the app to a workspace: This app is currently denied for installation. You can try requesting again with different scopes and outgoing domains.
If your app is denied you should reach out to your workspace administrators. They can approve the app manually from the app management page.
If you add a new OAuth scope or outgoing domain to your app you will need to re-deploy it. This will trigger a new installation request flow. This is expected. Workspace admins will need to approve the new changes in order for the updated version of your app to be installed. This will not affect current app installations but the new scope or domain won't function until the app is re-approved.
Admin Approval is required on this workspace.
? Would you like to send a request to the workspace admin for approval to install this app? (y/N)
Admins will be notified about the requested changes. They will also be able to see that the app had previously been approved.