Best practices for managing apps at scale
As your organization's use of Slack expands, so does the ecosystem of custom apps and integrations. While this empowers teams to be more productive, it can also introduce challenges related to security, governance, and scalability. Managing a growing number of apps without a clear strategy can lead to duplicated effort, inconsistent user experiences, and potential security vulnerabilities.
This guide outlines a set of best practices for managing your Slack apps at scale, ensuring your platform remains both powerful and secure. We'll explore how to leverage the full potential of the Slack CLI for lifecycle management, creating standardized app templates, implementing approval workflows, and using automation to handle bulk operations. We will also touch on how emerging AI tools can further streamline the your workflows.
Whether you're a developer building the next great integration or an administrator responsible for your organization's digital workspace, these practices will help you build and maintain a thriving, well-managed app ecosystem.
Embed security into the app lifecycleβ
Security shouldn't be an afterthought. A secure Slack ecosystem requires a proactive approach that integrates security principles directly into your development and management workflows, ensuring it's baked in from start to finish.
Secure secret managementβ
Your app's tokens, keys, and other credentials are highly sensitive. Never hardcode them directly into your application's source code or store them in non-secure locations.
- For development: Use local environment variables (
.env
files) to store secrets. Ensure your.gitignore
file includes.env
to prevent accidental commits. - For production: Use a dedicated secrets management solution. For CI/CD workflows, services like GitHub Actions Secrets, AWS Secrets Manager, or HashiCorp Vault are industry standards. This ensures that sensitive tokens are injected securely at build or runtime, rather than being stored in your codebase.
In the GitHub Actions example later in this guide, secrets.SLACK_SERVICE_TOKEN
is an example of this practice in action.
The principle of least privilegeβ
Every app should only have the minimum permissions (scopes) necessary to perform its function.
- In templates: Define a minimal set of scopes in your template's
manifest.json
file. This forces developers to consciously justify any additional permissions they need. - Scope policies: Create and document a clear policy that categorizes scopes.
- Always allowed: Low-risk scopes that can be used without special approval (e.g.,
commands
,chat:write
). - Requires approval: Higher-risk scopes that require manual review (e.g.,
channels:history
,users:read
). - Restricted: High-risk scopes that are forbidden or only allowed in exceptional circumstances (e.g.,
admin
).
- Always allowed: Low-risk scopes that can be used without special approval (e.g.,
- Regular audits: Use scripts (like those provided below) to regularly audit the scopes of all installed apps and flag any that violate your policies.
Continuous auditing and loggingβ
You can't secure what you can't see. Regular auditing is critical for maintaining a secure app ecosystem.
- Automate audits: Use the CLI and simple scripts to automate checks for common security issues, such as apps with overly permissive scopes, inactive collaborators who should be removed, or apps that haven't been updated in a long time.
- App activity logging: Your app's code should include comprehensive logging to track important events, such as who installed the app, what actions users are taking, and any errors that occur. This is invaluable for troubleshooting and for security incident investigations.
Read more on security best practices here.
Start with the CLIβ
The Slack CLI is the best way to manage your Slack apps through their entire lifecycle. It allows you to move away from manual configuration in a UI to managing a professional application lifecycle directly from your terminal, code editor, or automation platform of your choice. You can install the Slack CLI for Mac OS & Linux by running the following command from your terminal:
curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash
The Slack CLI installs Deno by default to support Slack apps using our more advanced automation features for customizing Workflow Builder. Deno is the runtime environment for our Run on Slack Infrastructure and allows you to deploy custom workflows directly to Slack.
If you're planning to build Slack apps using our Bolt framework for JavaScript, Python, or Java, you can skip the Deno installation by passing the -d flag as shown below:
curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash -s -- -d
If you're unsure about whether or not you need Deno, don't sweat it! We recommend skipping the installation for now. You can always reinstall the CLI in the future, no matter what you choose today! π
β¨ Check out the Slack CLI documentation for more installation options.
Use the CLI and simple scripts for bulk operationsβ
Need to know which apps in your organization are using the conversations:history
scope? Or who the collaborators are for each app? Now you can use the CLI and a tiny bit of scripting to speed up these bulk operations significantly. Below are examples in Bash and Python for listing all collaborators for every app in a workspace.
Examplesβ
Use Bash & Slack CLI to get collaborators for all apps for a given Team ID
#!/bin/bash
# This script lists all collaborators for every app installed in a specific Slack workspace.
# It requires the Slack CLI and jq (a JSON processor) to be installed.
# Set the Team ID for the workspace you want to inspect.
# You can get this by running `slack auth list`
TEAM_ID="T01234567"
echo "Fetching apps for team ${TEAM_ID}..."
# Get a list of all app IDs in the specified workspace.
# The `slack app list` command outputs JSON, which we parse with `jq`.
APP_IDS=$(slack app list --team ${TEAM_ID} --output json | jq -r '.[].app_id')
if [ -z "$APP_IDS" ]; then
echo "No apps found or failed to fetch apps for team ${TEAM_ID}."
exit 1
fi
echo "Found apps. Fetching collaborators..."
echo "-------------------------------------"
# Loop through each App ID to get its collaborators.
for APP_ID in $APP_IDS; do
echo "App ID: ${APP_ID}"
# Fetch and list collaborators for the current app.
# The output is formatted directly by the CLI's text output.
slack collaborator list --app ${APP_ID} --team ${TEAM_ID}
echo "-------------------------------------"
done
echo "Script finished."
Use Bash & Slack CLI to see all apps and their scopes for a given Team ID
#!/bin/bash
# This script provides an audit of all apps in a specific workspace,
# including their names, IDs, installation dates, and permission scopes.
# It requires the Slack CLI and jq (a JSON processor) to be installed.
# --- Configuration ---
# Set the Team ID for the workspace you want to audit.
# You can find your Team ID by running `slack auth list`
TEAM_ID="T01234567"
echo "Starting app audit for team ${TEAM_ID}..."
echo "=========================================="
# Fetch the list of apps as a single JSON object.
APPS_JSON=$(slack app list --team ${TEAM_ID} --output json)
# Check if the command succeeded and returned a valid JSON array.
if ! echo "$APPS_JSON" | jq -e 'if type=="array" then . else empty end' > /dev/null; then
echo "Failed to fetch app list or no apps found."
exit 1
fi
# Use jq to iterate over each app in the JSON array.
# The -c flag produces compact, single-line output for each object.
echo "$APPS_JSON" | jq -c '.[]' | while read -r app_json; do
# Extract app details from the JSON for the current app.
APP_NAME=$(echo "$app_json" | jq -r '.name')
APP_ID=$(echo "$app_json" | jq -r '.app_id')
TEAM_ID_FROM_APP=$(echo "$app_json" | jq -r '.team_id')
INSTALLED_ON=$(echo "$app_json" | jq -r '.installed_on')
echo "App Name: ${APP_NAME}"
echo " App ID: ${APP_ID}"
echo " Team ID: ${TEAM_ID_FROM_APP}"
echo " Installed: ${INSTALLED_ON}"
# Fetch the manifest for the current app to get its scopes.
MANIFEST_JSON=$(slack manifest info --app "${APP_ID}" --team "${TEAM_ID}" --output json)
# Extract the 'bot_scopes' array, and join its elements into a single comma-separated string.
# If scopes are not found, it will default to "N/A".
SCOPES=$(echo "$MANIFEST_JSON" | jq -r '.settings.bot_scopes | if . then join(", ") else "N/A" end')
echo " Scopes: ${SCOPES}"
echo "-----------------------------------------"
done
echo "=========================================="
echo "App audit finished."
Use Python & Slack CLI to get collaborators for all apps for a given Team ID
import subprocess
import json
import os
# This script lists all collaborators for every app installed in a specific Slack workspace.
# It requires the Slack CLI to be installed and authenticated.
# --- Configuration ---
# Set the Team ID for the workspace you want to inspect.
# You can find your Team ID by running `slack auth list` in your terminal.
TEAM_ID = "T01234567"
def run_slack_command(command):
"""Executes a Slack CLI command and returns the JSON output."""
try:
# The command is executed in a subprocess.
# stdout is captured, and stderr is piped to handle potential errors.
# We specify text=True to get output as a string.
result = subprocess.run(
command,
check=True,
capture_output=True,
text=True,
shell=True # Use shell=True for simplicity with complex commands
)
# The JSON output from stdout is parsed.
return json.loads(result.stdout)
except subprocess.CalledProcessError as e:
print(f"Error executing command: {' '.join(command)}\n{e.stderr}")
return None
except json.JSONDecodeError:
print(f"Failed to decode JSON from command: {' '.join(command)}")
return None
def main():
"""Main function to fetch apps and their collaborators."""
print(f"Fetching apps for team {TEAM_ID}...")
# Command to list all apps in the specified team and get JSON output.
list_apps_command = f"slack app list --team {TEAM_ID} --output json"
apps = run_slack_command(list_apps_command)
if not apps:
print("No apps found or failed to fetch apps.")
return
print("Found apps. Fetching collaborators for each...")
print("-------------------------------------")
# Iterate through each app found.
for app in apps:
app_id = app.get("app_id")
app_name = app.get("name")
print(f"App: {app_name} (ID: {app_id})")
# Command to list collaborators for the current app.
list_collabs_command = f"slack collaborator list --app {app_id} --team {TEAM_ID} --output json"
collaborators = run_slack_command(list_collabs_command)
if collaborators:
for collab in collaborators:
user_id = collab.get('user_id')
email = collab.get('email')
print(f" - Collaborator: {email} (ID: {user_id})")
else:
print(" - No collaborators found or failed to fetch.")
print("-------------------------------------")
print("Script finished.")
if __name__ == "__main__":
main()
Use custom templatesβ
Slack CLI supports creating apps from any accessible GitHub repository, allowing you to create starter templates tailored to your specific needs. Set pre-approved scopes, features, deploy targets, etc. Make updates in one spot, and apps can pull changes. See the Bolt for JS starter template for inspiration.
slack create policy-compliant-app --template=your-gh-org/your-slack-app-template-repo
β¨ See the Slack CLI documentation for the create
command.
Use scope policiesβ
Align on what scopes are always allowed
, allowed with approval
, and not allowed
. This policy should be well-documented in your template's README. You can set the always allowed
scopes within your template's manifest.json
file. Scope policies can also be aligned with an organization policy, connecting your app development process directly to your app approval process.
β¨ Ensure you have a clear process for developers to submit approval requests for scopes that are not pre-approved. See the Use app approvals section below to learn more.
Use deploy hooks for CI/CDβ
Ensure your app settings are synced and your app is reinstalled before pushing your code changes to production to ensure a smooth deployment process. In your templateβs .slack/hooks.json
file, add a deploy hook for deploying your application code to your provider of choice:
{
"hooks": {
"get-hooks": "npx -q --no-install -p @slack/cli-hooks slack-cli-get-hooks",
"deploy": "git push heroku main"
}
}
This hook tells the Slack CLI to execute the Heroku deployment command whenever the deploy process is triggered. The slack deploy
command will:
- Update your app settings if any changes were made to your
manifest.json
file - Reinstall the app if needed based on app settings changes
- Run the deploy hook to push the application code to Heroku
You can take this a step further by adding a corresponding GitHub Action to your template that runs slack deploy
on merges to the main
branch, providing a clear, consistent CI/CD process for every Slack app in your organization. Hereβs an example .github/workflows/deploy.yml
file:
name: Deploy Slack app
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: Install Slack CLI
run: |
curl -fsSL https://downloads.slack-edge.com/slack-cli/install.sh | bash
- name: Install Heroku CLI
run: |
curl https://cli-assets.heroku.com/install.sh | sh
- name: Deploy to Slack and Heroku
env:
SLACK_SERVICE_TOKEN: ${{ secrets.SLACK_SERVICE_TOKEN }}
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
run: slack deploy -s --token $SLACK_SERVICE_TOKEN
When is a reinstall required?β
The slack deploy
command is smart. It first checks your manifest.json
file for any changes that require the app to be reinstalled. A reinstallation is necessary when you change permissions or fundamental capabilities, as existing users must approve the new terms. Key changes that trigger a reinstall include:
- Changing scopes: Adding or removing scopes (e.g., adding
canvases:create
). - Enabling org-wide deployment: Setting
org_deploy_enabled
totrue
. - Adding or modifying event subscriptions: Subscribing to new events like
member_joined_channel
. - Adding or removing features: Enabling AI features for your app.
Understanding this behavior is crucial for avoiding unexpected disruptions for your users.
Make apps org-ready by defaultβ
Ensure your app templates are org-ready by setting the org_deploy_enabled
setting to true
in the manifest.json
file. This setting:
- ensures your apps are ready for Enterprise Grid
- allows you to align your app templates with an organization policy
- allows you to manage all app installations across workspaces from the admin dashboard
- enables sharing custom steps for Slack apps across your organization
- simplifies token storage
"settings": {
...existing settings
"org_deploy_enabled": true,
}
In the image of the admin dashboard here, you can identify which app is installed at the org level because in the access level column it says "organization."
Learn more about org-ready apps here.
Use app approvalsβ
To effectively manage apps at scale, workspace administrators should establish a clear approval process. By default, any member can install an app, but enabling app approvals provides essential control and security.
Enable app approval requirementβ
The first step is to require app approvals in your workspace. Follow these steps to do so:
- Navigate to your organization dashboard.
- Select Workspaces.
- Select the workspace, then Manage, then Manage apps.
- Select App Management Settings and toggle on Require App Approval.
Once enabled, members can only install apps that have been pre-approved; all other apps must be submitted for approval.
Curate app listsβ
Admins can proactively manage the app ecosystem by pre-approving or restricting specific apps.
- Pre-approving an app allows any member to install it without needing further permission.
- Restricting an app prevents it from being installed or requested.
Delegate responsibilitiesβ
To avoid bottlenecks, you can designate specific "App Managers" to help review and process app requests. These can be individual members or entire user groups.
Control Sign in with Slackβ
Admins can manage whether members are permitted to use their Slack credentials to sign into third-party services.
Use automation rulesβ
For maximum efficiency, set up automation rules to handle app requests automatically.
- Rate scopes: Before creating rules, rate the permission scopes that apps request as "High", "Medium", or "Low" risk. This allows you to build rules that automatically approve apps requesting low-risk permissions while flagging higher-risk apps for manual review. (This should align with your scope policies!)
- Configure rules: Create rules that automatically approve or restrict apps based on various conditions, such as their requested scopes, whether they are internal or from the Marketplace, or specific app IDs.
- Manage and order rules: Rules are evaluated in the order they are listed, so you should prioritize them carefully. You can activate, pause, edit, or remove rules as your needs change.
By implementing a clear approval workflow with smart automation, administrators can maintain strong security and governance over their workspace without creating unnecessary friction for their members.