The new Slack platform is in beta. Your feedback is most welcome.

Beta migration guide

With the release of v1.9.0 we've introduced some breaking changes for existing developers in our private beta.

If you've been building apps as part of our private beta, you'll now need to add Workflows and Triggers to your apps.

In this migration guide, we'll walk through how to migrate the previous version of our Reverse String demo app to a modern version that leverages Workflows and Triggers.

Understanding what changed

The previous version of the Reverse String app relied on automatically generated apps and shortcuts to power functions. With the introduction of Workflows and Triggers, we need to think about our app a little differently.

Whereas before a Function could be created and a Global shortcut automatically made, now we must add that Function as a step in a Workflow and then invoke that Workflow with a Trigger. Each of these are aspects of our app that we now define in code.

Have 2 minutes to provide some feedback?

We'd love to hear about your experience with the new Slack platform. Please complete our short survey so we can use your feedback to improve.

The core functionality demonstrated by the Reverse String demo is how a user can be presented with a modal that collects data and then that data can be used inside of a function—the results of which can be used as well.

To replicate this functionality, we will build a Workflow that uses Interactivity components and that calls our Function. Then, we'll setup a Trigger to invoke that Workflow.

At the end, we'll try out our app by invoking the Workflow.

Ready? Let's go!

Step 1: Update all dependencies

The first thing we'll do is update to the latest version of slack and ensure we're using the most recent version of the SDK.

Update the slack CLI by running slack update. When you're done, run slack version and ensure you see v1.9.0.

Update to the latest version of the SDK by going into the import_map.json file and ensuring the entry for deno-slack-sdk points to version 0.1.0. It should look something like this:

  "imports": {
    "deno-slack-sdk/": "",
    "deno-slack-api/": ""

Step 2: Define and implement a Workflow

In your Manifest file (manifest.ts), import DefineWorkflow and then create a new Workflow:

// manifest.ts

import { 
    DefineWorkflow, // Add this
} from "slack-cloud-sdk/mod.ts";

export const TestReverseWorkflow = DefineWorkflow({
  callback_id: "test_reverse",
  title: "Test Reverse Function",
  description: "test the reverse function",
  input_parameters: {
    properties: {
      interactivity: {
        type: Schema.slack.types.interactivity, // This gets passed in through the trigger
    required: ["interactivity"],

You can learn more about the interactivity input property here. We're using it to mimic the former behavior of automatically sending a form to a user when they execute a Global shortcut. Now, we must explicitly define this interactivity component as well as implement it—which we will do next:

// manifest.ts, just after the Workflow definition

const formData = TestReverseWorkflow.addStep(Schema.slack.functions.OpenForm, {
  title: "Reverse string form",
  submit_label: "Submit form",
  description: "Submit a string to reverse",
  interactivity: TestReverseWorkflow.inputs.interactivity,
  fields: {
    required: ["channel", "stringInput"],
    elements: [
        name: "stringInput",
        title: "String input",
        type: Schema.types.string,
        is_required: true,
        name: "channel",
        title: "Post in",
        type: Schema.slack.types.channel_id,
        is_required: true,

The first step we've added to our Workflow is the Built-in function OpenForm, which opens a form modal for the user.

Now that we've collected some data, let's add our Custom function as the next step in the Workflow:

// manifest.ts, just after the OpenForm step

const reverseStep = TestReverseWorkflow.addStep(ReverseFunction, {
  stringToReverse: formData.outputs.fields.stringInput,

Great! Now we've got one step that collects user input, and a second step that does something with that user input. Let's create a third and final step that emits the result of the second step to the channel that the user specified in the first step:

//manifest.ts, just after the ReverseFunction step

TestReverseWorkflow.addStep("slack#/functions/send_message", {
  message: reverseStep.outputs.reverseString,

Our Workflow has now been defined and implemented. The last step is to add it to our Manifest so that our app knows about it:

// manifest.ts, at the bottom of the file where Manifest is exported

export default Manifest({
  // ...
  workflows: [TestReverseWorkflow], // Add this

Step 3: Create a trigger

With our new Workflow created, all that's left is to create a Trigger to invoke it.

Before we can create any triggers, we need to deploy our app at least once. Let's do that now:

slack deploy

After the CLI is done packaging up your app and deploying it, create a new Typescript file at the root of your project. For instructional purposes, let's call this file link_trigger.ts (the name of the file doesn't affect anything):

// link_trigger.ts

import { ValidTriggerTypes } from "deno-slack-api/types.ts";

const trigger: ValidTriggerTypes = {
  type: "shortcut",
  name: "Reverse a String",
  description: "Starts the workflow to test reversing a string",
  workflow: "#/workflows/test_reverse",
  inputs: {
    interactivity: {
      value: "{{data.interactivity}}",

export default trigger;

Since we're replicating the functionality of our previous Reverse String project, we create a shortcut trigger type to replace the old auto-generated shortcut with a new Link trigger.

With a Trigger defined, we can now build the Trigger using the CLI:

slack trigger create --trigger-def link_trigger.ts

The output will look something like this:

⚡ Trigger created
     Trigger ID:   Ft0123ABC456
     Trigger Type: shortcut
     Trigger Name: Reverse a String
     Shortcut URL:

You can copy that Shortcut URL and paste it in your workspace to run your Workflow. You can also bookmark that Shortcut URL, send it to someone in a message, or add it to a file somewhere.

Note: these new shortcuts do not appear in the global shortcuts menu.

And that's it! To review all of this code as part of a fully functional app that you can download and use as a template, check out the repo on Github.