A step-by-step tutorial to stop a discord bot from sleeping on Render's free tier — the real cause, the fix, and a working code example.
How to Stop Your Discord Bot From Sleeping on Render's Free Tier
You've deployed your Discord bot to Render's free tier, it worked for a bit, and now it's going offline — sometimes after a few minutes, sometimes randomly. This is one of the most common issues developers hit deploying a bot for the first time, and it has a specific, well-understood cause and a fix you can ship in under ten minutes.
Table of Contents
- Why This Happens on Render Specifically
- Confirming This Is Your Actual Problem
- Step 1: Install StayPresent
- Step 2: Wrap Your Bot's Entry Point
- Step 3: Read Render's Assigned Port
- Step 4: Set Your Render Start Command
- Step 5 (Optional): Prevent Inactivity Sleep Specifically
- Verifying It Worked
- FAQs
- Conclusion
Why This Happens on Render Specifically
Render's free-tier web services are checked for health over HTTP, and free services also spin down after a period without incoming traffic. A discord.py bot connects outward to Discord's gateway — it never opens an HTTP port of its own, which is completely normal bot behavior. Render's health checker, seeing nothing respond on the expected port, has no way to know the bot is actually working fine internally. It just sees silence, and reacts accordingly.
Confirming This Is Your Actual Problem
If your bot's entry point goes straight into bot.run(TOKEN) with nothing else, and Render's dashboard shows the deployment as unhealthy or repeatedly restarting with no matching error in your bot's own logs, this is almost certainly it.
Step 1: Install StayPresent
pip install staypresent[prod]
Add it to your requirements.txt as well:
staypresent[prod]
discord.py
Step 2: Wrap Your Bot's Entry Point
Keep your existing bot code in bot.py completely unchanged. Create a new main.py:
import os
import staypresent
staypresent.web.json({"status": "running"})
staypresent.run("bot.py")
Step 3: Read Render's Assigned Port
Render injects a PORT environment variable — your app needs to bind to it dynamically, not a hardcoded value:
import os
import staypresent
staypresent.web.json({"status": "running"})
staypresent.run(
"bot.py",
port=int(os.getenv("PORT", 8080)),
)
Step 4: Set Your Render Start Command
In Render's service settings, set the start command to run your new entry point:
python main.py
Deploy. Render now has something to check on, and your bot's own logic — the actual discord.py code — didn't change at all.
Step 5 (Optional): Prevent Inactivity Sleep Specifically
Solving the port requirement alone stops Render from marking the deployment unhealthy. If Render's free tier is also spinning your specific service down after inactivity, add a self-ping targeting your own public URL:
import os
import staypresent
staypresent.web.json({"status": "running"})
staypresent.cron("https://your-app-name.onrender.com", interval=240)
staypresent.run(
"bot.py",
port=int(os.getenv("PORT", 8080)),
)
This has to target your actual onrender.com URL — pinging 0.0.0.0 or 127.0.0.1 never leaves the machine and won't count as external activity.
Verifying It Worked
After deploying, check Render's dashboard — the service should show as healthy rather than restarting in a loop. You can also visit your app's /health endpoint directly in a browser; it should return {"status": "ok"}. If you're on a recent version of StayPresent, /status shows a live status page with uptime history, which is a quick way to confirm the bot is staying up over time rather than just checking once.
FAQs
Do I need to change my bot's actual Discord logic?
No — bot.py stays exactly as it was. Only the entry point Render runs (main.py) is new.
Does this work for Telegram bots too?
Yes — the same pattern applies to any long-running Python process that doesn't open its own HTTP port, regardless of which platform's API it talks to.
Will this cost anything?
No — StayPresent is MIT licensed and free, and this setup doesn't require upgrading your Render plan.
Conclusion
A Discord bot sleeping on Render's free tier is almost always a missing HTTP port, not a bug in your bot. Wrapping your existing bot.py in staypresent.run(), reading Render's PORT variable, and optionally self-pinging your public URL solves it completely, with zero changes to your bot's actual code.
pip install staypresent[prod]
Top comments (0)