Discloud will keep your bot alive — it won't keep it healthy
Discloud's auto-restart keeps a crashed Discord bot online, but it can also mask a memory leak. A look at the manifest, RAM sizing, and telling transient crashes from systemic ones.
19 Jan 2026, 03:47 UTC

A familiar pattern with small Discord bots: the process crashes at 3 a.m., the host restarts it, and everything looks fine — until it crashes again the next night, and the night after. Each restart "works," so nothing gets fixed. On Discloud, a managed host aimed at Discord bots and small web apps, this pattern has a specific shape, because the platform's two most important knobs — a RAM allocation and an auto-restart flag — sit in a single config file you ship with your code.
The argument here: auto-restart is genuinely useful for transient failures, but it will happily mask a memory leak or a reconnect storm for weeks. Treat restarts as a signal to investigate, not a fix, and spend your sizing effort on making the bot memory-lean rather than buying headroom.
The entire deploy contract is one text file
Instead of renting a VPS and configuring a runtime, you zip your project and upload it — through a web dashboard, a CLI, a VS Code extension, or Discloud's own Discord bot. Inside the zip sits a manifest, discloud.config, that tells the platform what it's running:
NAME=my-moderation-bot
TYPE=bot
MAIN=index.js
RAM=100
AUTORESTART=true
VERSION=latestThese fields declare the app's name, that it's a bot rather than a site, the entry file, the requested RAM in megabytes, whether the process should be restarted when it exits, and the runtime version. The platform provisions everything from this file, which makes it the most important ten lines of your project. One caveat: field names and accepted values have changed over time, so confirm the current schema in Discloud's docs before your first upload rather than copying an old example — including this one.
Updates don't require rebuilding the whole archive; a commit-style push sends just the changed files, which fits the edit-restart-test loop of bot development. The CLI consumes a per-user API token: generate it in the dashboard, keep it out of git, and run discloud --help to confirm the exact subcommands on your installed version, since spellings have shifted between releases.
# from your project root, after logging in with your API token
discloud upload ./bot.zipRAM is the sizing decision you'll actually feel
Discloud's free capacity is small — commonly cited around 100 MB — with paid plans raising the ceiling. Plan details change, so check the current plans page before committing to a number. That constraint flips usual VPS instincts: on a 4 GB VPS, an unbounded in-memory cache is a problem you hit next quarter; on a 100 MB allocation, it's a problem you hit on launch day.
Too little RAM and the runtime's out-of-memory killer terminates your process — and AUTORESTART=true quietly brings it back, converting a visible failure into an invisible loop. Too much RAM and you burn quota you didn't need. The practical move is designing for a small footprint: lazy-load data instead of caching eagerly, stream large payloads rather than buffering them, and never hold bulk data in memory when you can fetch on demand.
A worked example: the cache that ate the quota
Here's a common offender in a Node.js bot — code that remembers every display name it ever sees:
// before: the Map only ever grows
const nameCache = new Map();
client.on("guildMemberUpdate", (oldM, newM) => {
nameCache.set(newM.id, newM.displayName);
});On a busy bot this grows without bound until the OOM killer arrives. A bounded cache using JavaScript's Map insertion order takes a few lines:
// after: keep the 500 most recent entries, evict the oldest
const MAX_ENTRIES = 500;
const nameCache = new Map();
client.on("guildMemberUpdate", (oldM, newM) => {
nameCache.delete(newM.id); // re-insert to refresh recency
nameCache.set(newM.id, newM.displayName);
if (nameCache.size > MAX_ENTRIES) {
nameCache.delete(nameCache.keys().next().value);
}
});To tell a leak from a transient crash, log memory on a schedule and watch the trend alongside the restart cadence in the dashboard:
setInterval(() => {
const { rss, heapUsed } = process.memoryUsage();
console.log(`mem rss=${Math.round(rss / 1e6)}MB heap=${Math.round(heapUsed / 1e6)}MB`);
}, 60_000);If RSS climbs steadily and the app restarts every few hours, that's a leak signature — fix the code rather than raising RAM. If RSS is flat and restarts are rare, auto-restart is doing its real job: absorbing one-off failures like network blips. Wire up error tracking (Sentry or similar) either way, because a restart loop that only logs to the dashboard is easy to miss.
What you give up, and a sane first deploy
The trade-off is real: no shell access, no Dockerfiles, no custom infrastructure. Cron jobs, background workers, and databases beyond what the platform offers need another home. Lock-in is modest — the app itself is a plain Node.js or Python project — but the manifest and deploy flow are Discloud-specific. One nice touch: apps declared with TYPE=site get an HTTPS subdomain, so a tiny status page can share the bot's pipeline; custom domains and larger tiers are tied to paid plans, so verify current terms.
A first deploy worth doing, in order:
- Confirm the
discloud.configschema and current free-tier RAM in the official docs and plans page. - Zip a minimal bot with the manifest, deploy via the CLI, and check the dashboard shows it online with logs streaming.
- Stop the process deliberately and confirm auto-restart brings it back.
- Add the memory log line and error tracking before the bot has users, not after the 3 a.m. loop starts.
Do that, and auto-restart stays what it should be: a safety net for transient failures, with you still holding the shovel when something is genuinely wrong.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.