Prepare and upload your Discord bot¶
Your Discord bot service runs the code you upload. Zaroz provides the runtime, the persistent storage, and the process supervision that keeps your bot online; you provide the bot's source files. This page walks through what happens on each start, where your files need to go, and what differs between the Node.js, Python, Bun, Deno, Java, and Other runtimes.
How a bot start works¶
Every time your bot starts (the first boot, a restart after a crash, or a redeploy), the container does the same three things, all from your bot's storage folder:
- Change into the storage folder. This is where your uploaded files live and the working directory for everything below.
- Run the install step for your runtime (for example
npm installfor Node.js). Some runtimes have no install step; see What runs for each runtime. - Run your start command (for example
node index.js). This is the process that stays alive and connects to Discord.
If the process exits, the container restarts it and the cycle runs again. That is why a broken dependency or a bad start command shows up as a crash loop rather than a one-time error.
Where your files go¶
Your files must sit in the root folder, not inside a subfolder.
Open the Files tab on your service to upload them through the browser, or connect over SFTP with the credentials shown on that tab. In both places the root of your bot's storage is /, shown as / Home in the file manager. Your layout must look like this:
/ ← the root folder, shown as "/ Home"
├── index.js ← your entry file, directly in the root
├── package.json
├── package-lock.json
└── src/
└── ...
Why you may also see /data
Inside the container, that same folder is mounted at /data, so log lines and error messages from your bot often show paths like /data/index.js. It is the same place: the root / in the Files tab is /data inside the container. Upload to /, and your bot reads it as /data.
Do not nest your project in a subfolder
The install step and start command run in the root of your storage. If your files land one level too deep, for example /my-bot/index.js, the start command node index.js runs in the root, finds nothing, and the bot crash-loops.
This is one of the most common issues we see, and it usually happens when a .zip extracts into a folder named after the project. If that happens, open the extracted folder in the Files tab, select everything inside it, and move it up one level so the files sit directly in /.
Uploading a zip
You can upload a .zip and extract it from the Files tab. After extracting, check that index.js (or your entry file) is in the root and not inside a nested folder. Do not upload node_modules/ — it is reinstalled on the server and only slows the upload.
What runs for each runtime¶
You chose a runtime during setup. It decides the base image, the install step, and the default start command. You can see and change your bot's current runtime and start command any time on the Configuration tab.
- Install step:
npm install --if-present(skipped if there is nopackage.json). - Default start command:
node index.js. - Dependencies come from your
package.json. Commit apackage-lock.jsonfor reproducible installs. - Common alternative start commands:
npm start,node bot.js,node src/index.js.
- Install step:
pip install .when apyproject.tomlis present, otherwisepip install -r requirements.txt. - Default start command:
python main.py. - List every dependency in
requirements.txtwith pinned versions. Thepipcache is kept on your volume, so unchanged dependencies are not re-downloaded on the next start. - Common alternative start commands:
python bot.py,python -m bot.
- Install step:
bun install --production. - Default start command:
bun run index.js. - Dependencies come from your
package.json. - Common alternative start commands:
bun start,bun run src/index.ts.
- Install step: none. Deno fetches and caches your imports on the first run.
- Default start command:
deno run --allow-all main.ts. --allow-allis the easy default. Narrow it (for example--allow-net --allow-env) once you know which permissions your bot actually needs.
- Install step: none. There is no build step on the server, so upload a pre-built
.jar. - Default start command:
java -jar bot.jar. - Either name your jar
bot.jar, or change the start command on the Configuration tab to match your filename, for examplejava -jar my-bot-1.0.jar.
- Install step: none automatic. We mark
start.shexecutable and run it. - Default start command:
./start.sh. - You get a plain shell: Alpine on the Lightweight image, Debian on Standard. Install whatever you need from inside your script, using
apkon Alpine orapt-geton Debian.
Runtime versions
The major versions are fixed: Node 22, Python 3.13, Java 21, and current Bun/Deno. The compatibility choice (Lightweight vs Standard) changes the operating-system base, not the language version. See Choose the right compatibility for when to pick Standard.
Choosing your start command¶
During setup you either pick one of the per-runtime presets or type a custom command. If you left it on the default and your entry file has a different name, the bot will not start.
To change it later, open the Configuration tab, update the start command, and restart. The new command takes effect on the next start.
The start command is run by a shell in the root of your storage, so ordinary shell syntax works. Keep it to a single foreground process that stays alive — do not background it with &, or the container will think the bot exited and restart it.
Keep your bot token safe¶
Your bot token is a password. Anyone who has it can control your bot.
- Never hardcode the token into a file you might commit to Git or share in a support ticket.
- Read it from an environment variable or a config file that stays on the server.
- If a token is ever exposed, reset it immediately in the Discord Developer Portal under Bot → Reset Token, then update it on the server.
Do not paste your token into chat or screenshots
Support will never ask for your bot token. If you need help, describe the error from the Console tab instead — it does not need to include the token.
What survives a restart¶
Everything in your storage folder is persistent. It survives restarts, crash recovery, and redeploys. That includes:
- Your uploaded source files.
- Installed dependencies (
node_modules/, thepipcache, Deno's module cache). - Any files your bot writes, such as a SQLite database or a JSON config.
Because installed dependencies persist, a start that fails halfway can leave a broken node_modules/ (or __pycache__/, a partial virtualenv, and so on) behind. If a bot keeps failing to install after you have fixed the underlying problem:
- Open the Files tab.
- Delete
node_modules/(or the equivalent broken directory). - Restart. The install step rebuilds it from scratch.
Watch it start¶
Open the Console tab to follow a start in real time. You will see the install step run, then your start command, then your bot's own log output. When something goes wrong, the error is here: a missing module, a syntax error, an invalid token, or a start command pointing at a file that does not exist.
Fix the problem in your files, restart, and the container picks up the change on the next start.
Next steps¶
- Choose the right compatibility — when Lightweight is not enough and how to switch.
- Monitor a Minecraft order from Discord — a worked example bot using the Zaroz API.