Startup → Docker Image → Node.js 24 (or Bun). Then upload these files.
The files
package.json lists your packages:
{
"name": "my-bot",
"main": "index.js",
"dependencies": {
"discord.js": "^14.16.0",
"dotenv": "^16.4.5"
}
}
index.js is the bot:
require('dotenv').config();
const { Client, Events, GatewayIntentBits } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.once(Events.ClientReady, (c) => console.log(`Logged in as ${c.user.tag}`));
client.login(process.env.DISCORD_TOKEN);
.env holds the token: DISCORD_TOKEN=your-token-here.
Don’t upload node_modules. On start we run npm install (or pnpm / yarn when you have their lock file), then start your bot.
How we start it
- Main file in the Startup tab, if you set one.
- Otherwise your
startscript frompackage.json(npm start). - Otherwise
mainfrompackage.json, or the first ofindex.js,bot.js,main.js,src/index.js.
TypeScript
Three ways, pick one:
- Set Main file to
index.ts(or name itindex.ts). It runs withtsx, no build step. - Have a
buildscript (liketsc) and astartscript (likenode dist/index.js) inpackage.json: we runnpm run build, thennpm start. - Pick Bun: it runs
.tsfiles directly and reads.envby itself (nodotenvneeded).
Good to know
- Message content: to read messages, add
GatewayIntentBits.GuildMessagesandGatewayIntentBits.MessageContent, and switch on Message Content Intent in the Developer Portal → your app → Bot. - Slash commands register with a separate script (often
deploy-commands.js). Run it once from your computer, or set Own start command tonode deploy-commands.js && node index.js. - Music bots need
ffmpeg. It’s already installed. - Stop sends Ctrl+C: listen for
process.on('SIGINT', …)to save data before the bot closes.
More help: Run your Discord bot 24/7.