I’m trying to host both a Flask application and a Discord bot on Heroku at the same time, but I’m running into issues with the Procfile configuration.
My current setup:
server.py (main file):
import threading
from flask import Flask
import discord_client
webapp = Flask(__name__)
@webapp.route('/')
def home():
return 'Server is running'
def start_web():
webapp.run(host='0.0.0.0', port=5000)
def launch_async():
web_thread = threading.Thread(target=start_web)
web_thread.daemon = True
web_thread.start()
discord_client.py:
import discord
from discord.ext import commands
class DiscordClient(commands.Bot):
def __init__(self):
intents = discord.Intents.default()
intents.message_content = True
super().__init__(command_prefix='$', intents=intents)
async def on_ready(self):
print(f'Bot connected as {self.user}')
client = DiscordClient()
@client.command(name='hello')
async def greet(ctx):
await ctx.send('Hello there!')
The problem: When I use web: gunicorn server:webapp in my Procfile, only the Flask app runs but the Discord bot stays offline. If I change it to web: python server.py, the bot works but the web server doesn’t respond to requests.
This setup works perfectly on other platforms like Railway, but Heroku seems to handle things differently. Has anyone successfully deployed both services together on Heroku? What’s the correct way to configure this?
Your threading setup looks good, but you’ve got a major problem - you’re importing discord_client but never actually starting the bot. After you spin up the web thread in launch_async, add discord_client.client.run(TOKEN) where TOKEN comes from your environment variables. Ditch the web_thread.daemon = True line. Sure, it stops hanging on shutdown, but it’ll also kill your Discord bot randomly if the main thread exits. Handle shutdown properly instead. One heads up - Heroku web dynos go to sleep after 30 minutes without traffic, which kills both your Flask app and bot. You’ll need a keep-alive ping or move the bot to a worker dyno if this becomes an issue.
Had this exact problem last year. Heroku’s web dyno expects your Flask app to bind to the PORT environment variable, not a hardcoded port. Your threading’s right, but fix the Flask config. Change your start_web function to webapp.run(host='0.0.0.0', port=int(os.environ.get('PORT', 5000))) and import os. You’re importing discord_client but never starting the bot. Add discord_client.client.run(os.environ.get('DISCORD_TOKEN')) after starting your web thread. Your Procfile should be web: python server.py since you’re handling both services in the same process. Skip gunicorn - it only serves Flask and ignores your threading logic. Make sure PORT and DISCORD_TOKEN are set in Heroku’s config vars. Been running stable for months with this setup.
asyncio’s probably causing issues here. discord.py uses asyncio but you’re mixing it with threading for flask. Use asyncio.create_task() instead of threading to run both services. Also, you need to call launch_async() somewhere in your server.py - I don’t see it in your code.