Migrating apps from Hubot to Bolt

    Bolt was created to reduce the time and complexity it takes to build Slack apps. It provides Slack developers a single interface to build using modern features and best practices. This guide is meant to step you through the process of migrating your app from using Hubot to Bolt.

    If you already have an app with a bot user or if you’re looking for code samples that translate Hubot code to Bolt code, you may find it valuable to start by reading through the example script in the Bolt repository.

    Setting the stage

    When translating a Hubot app to Bolt, it’s good to know how each are working behind the scenes. Slack’s Hubot adapter is built to interface with the RTM API, which uses a WebSocket-based connection that sends a stream of workspace events to your Hubot app. The RTM API is not recommended for most use cases since it doesn’t include support for newer platform features and it can become very resource-intensive, particularly if the app is installed on multiple or large Slack teams.

    The default Bolt receiver is built to support the Events API, which uses HTTP-based event subscriptions to send JSON payloads to your Bolt app. The Events API includes newer events that aren’t on RTM and is more granular and scalable. It’s recommended for most use cases, though one reason your app may be stuck using the RTM API could be that the server you’re hosting your app from has a firewall that only allows outgoing requests and not incoming ones.

    There are a few other differences you may want to consider before creating a Bolt app:

    • The minimum version of Node for Bolt is v10.0.0. If the server you’re hosting your app from cannot support v10, it’s not possible to migrate your app to Bolt at the moment.
    • Bolt doesn’t have support for external scripts. If your Hubot app uses external scripts that are necessary to your app’s functionality or deployment, you probably want to stay with Hubot for now. If you aren’t sure whether your app has any external scripts, you can check the external-scripts.json file. As we continue to invest in Bolt, we are thinking about the future and how to make development and deployment of Slack apps easier. If there’s a valuable external script that your app uses, we’d love to hear what it is in the dedicated Github issue.
    • Hubot apps are written in Coffeescript, which transpiles into Javascript. We decided to write Bolt in Typescript to give access to rich type information. Bolt apps can be developed using Typescript or Javascript. The example script shows you how your Coffeescript may translate to Javascript. If your app is more than a few simple scripts, it may be worth looking into projects like Decaffeinate to convert your CoffeeScript to Javascript.

    Configuring your bot

    If you have access to an existing Slack app with a bot user, you can jump ahead to the next section. If you aren’t sure, go to your App Management page and check whether your Hubot app is there. If it is, you can use the credentials from that app (go ahead and skip to the next section). Otherwise, we’ll walk you through creating a Slack app.

    Create a Slack app

    The first thing you’ll want to do is create a Slack app.

    💡We recommend using a workspace where you won’t disrupt real work getting done — you can create a new one for free.

    After you fill out your app’s name and pick a workspace to install it to, hit the Create App button and you’ll land on your app’s Basic Information page.

    This page contains an overview of your app in addition to important credentials you’ll need later, like the Signing Secret under the App Credentials header.

    Look around, add an app icon and description, and then let’s start configuring your app 🔩

    Add a bot user

    On Slack, Hubot apps employ bot users which are designed to interact with users in conversation.

    To add a bot user to your new app, click Bot Users on the left sidebar and then Add A Bot User. Give it a display name and username, then click Add Bot User. There’s more information about what the different fields are on our API site.

    Configure what your bot will hear

    The Events API is a bot’s equivalent of eyes and ears. It gives a bot a way to react to posted messages, changes to channels, and other activities that happen in Slack.

    ⚠️Before you configure your bot’s events, you’ll need a public URL. If you’ve never created a Bolt app or never used the Events API, it’d be helpful to go through setting up your local Bolt project and setting up events in the Getting Started guide.

    Listening for messages

    All Hubot apps can listen to messages by default, so we need to configure your bot user to do the same.

    After walking through setting up events, your Request URL should be verified. Scroll down to Subscribe to Bot Events. There are four events related to messages: message.channels (listens for messages in public channels), message.groups (listens for messages in private channels), message.im (listens for messages in the App Home/DM space), and message.mpim (listens for messages in multi-person DMs).

    If you only want your bot to listen to messages in channels, you can listen to message.channels and message.groups. Or if you want your bot to listen to messages from everywhere it is, choose all four message events.

    After you’ve added the kinds of message events you want your bot to listen to, click Save Changes.

    Listening for other events

    Your Hubot app may have responded to other events depending on what functionality you used. Look through your script and identify any places where your script uses react, respond, or presenceChange:

    • If your app uses respond, subscribe to the app_mention event. This listens for any time your bot user is mentioned.
    • If your app uses react, subscribe to the reaction_added event. This listens for any time a reaction is added to a message in channels your bot user is in.
    • If your app uses presenceChange, there is no corresponding event. If this event is important to your bot’s functionality, you may have to continue using Hubot or modify the app’s logic.

    💡An added benefit to Bolt is you can listen to any Events API event. So after you’re done migrating, you can listen to more events like when a user joins the workspace or when a user opens a DM with your app.

    After you added events that correspond to your app’s functionality, click Save Changes.

    Changes to script interfaces

    Bolt’s interface was designed to conform to the Slack API language as much as possible, while Hubot was designed with more generalized language to abstract multiple services. While the interfaces are similar, converting a Hubot script to a Bolt one still requires some code changes.

    Bolt doesn’t use res or expose the raw request from Slack. Instead, you can use the payload body from payload, or common functionality like sending a message using say().

    ⚙️To make it easier, we’ve created a sample script on Github that showcases Hubot’s core functionality using equivalent functionality written for Bolt.

    Listening to patterns using message()

    Hubot scripts use hear() listen to messages with a matching pattern. Bolt instead uses message() and accepts a string or RegExp for the pattern.

    👨‍💻👩‍💻Anywhere where you use hear() in your code, change it to use message()

    Read more about listening to messages.

    Responding with a message using say() and respond()

    Hubot scripts use send() to send a message to the same conversation and reply() to send a message to the same conversation with an @-mention to the user that sent the original message.

    Bolt uses say() in place of send(), or respond() to use the response_url to send a reply. To add an @-mention to the beginning of your reply, you can use the user ID found in the context object. For example, for a message event you could use say('<@${message.user}> Hello :wave:')

    The arguments for Hubot’s send() and Bolt’s say() are mostly the same, although say() allows you to send messages with interactive components like buttons, select menus, and datepickers.

    👨‍💻👩‍💻Anywhere where you use send() in your code, change it to use say()

    Read more about responding to messages.

    respond and react

    In the previous section, you should have subscribed your app to the app_mention event if your Hubot script uses respond(), and reaction_added if you uses react().

    Bolt uses a method called event() that allows you to listen to any Events API event. To change your code, you’ll just change any respond() to app.event(‘app_mention’) and any react() to app.event(‘reaction_added’). This is detailed more in the example script.

    👨‍💻👩‍💻Anywhere where you use respond() in your code, change it to use app.event(‘app_mention’). Anywhere you use react, change it to app.event(‘reaction_added’).

    Read more about listening to events.

    Using Web API methods with Bolt

    In Hubot, you needed to import the WebClient package from @slack/client. Bolt imports a WebClient instance for you by default, accessible from app.client.

    To use the built-in WebClient, you’ll need to pass the token used to instantiate your app or the token associated with the team your request is coming from. This is found on the context object passed in to your listener functions. For example, to add a reaction to a message, you’d use:

    app.message('react', async ({ message, context }) => {
      try {
          const result = await app.client.reactions.add({
          	  token: context.botToken,
            name: star,
            channel: message.channel,
            timestamp: message.ts
      catch (error) {

    👨‍💻👩‍💻Change your Web API calls to use the built-in client at app.client.

    Read more about using the Web API with Bolt.

    Using middleware with Bolt

    Hubot has three kinds of middleware: receive (runs before any listeners are called), listener (runs for every matching listener), and response (runs for every response sent).

    Bolt only has two kinds of middleware — global and listener:

    With Bolt, both kinds of middleware must call next() to pass control of execution from one middleware to the next. If your middleware encounters an error during execution, you can pass an Error to next() and the error will be bubbled up through the previously-executed middleware chain.

    To migrate your existing middleware functions, it’s evident that Hubot’s receive middleware aligns with the use case for global middleware in Bolt. And Hubot and Bolt’s listener middleware are nearly the same. To migrate Hubot’s response middleware, you can use a Bolt concept called a post-process function.

    If your middleware needs to perform post-processing of an event, you can call next() with a post-processing function rather than it calling it with undefined. A post-processing function must call done() in the same way a middleware function must call next() (and can also be called with an Error).

    Migrating the brain to the conversation store

    Hubot has an in-memory store called the brain. This enables a Hubot script to get and set basic pieces of data. Bolt uses something called a conversation store, which is a global middleware with a get()/set() interface.

    The default, built-in conversation store uses an in-memory store similar to Hubot, with the ability to set an expiration time in milliseconds. There are two ways to get and set conversation state:

    • Call app.convoStore.get() with a conversation ID to retrieve the state of a conversation, and call app.convoStore.set() with a conversation ID, conversation state (key-value pair), and an optional expiresAt time in milliseconds.
    • In listener middleware, call context.updateConversation() with the updated conversation state, or use context.conversation to access the current state of the conversation.

    If there is more than one instance of your app running, the built-in conversation store will not be shared among the processes so you’ll want to implement a conversation store that fetches conversation state from a database.

    Read more about conversation stores.

    Next steps

    If you’ve made it this far, it means you’ve likely converted your Hubot app into a Bolt app! ✨⚡

    Now that you have your flashy new Bolt app, you can explore how to power it up:

    • Consider adding interactivity like buttons and select menus. These weren’t supported by Hubot and will allow your app to include contextual actions when sending messages to Slack.
    • Read the documentation to explore what else is possible with Bolt.
    • Check out our sample app that shows you how to use events and interactive components.

    And if you have difficulties while developing, reach out to our developer support team to at developers@slack.com, and if you run into a problem with the framework open an issue on Github.