Step 1 of 5Create the application0 done

From the download to a bot that is online

You have the project. What is left is a Discord account, four screens in a settings page, and one command in a terminal. Every step says what you should be seeing when it worked, so you can tell where it went wrong instead of starting over.

  1. 01 · 1 minCreate the application
  2. 02 · 1 minGet the token
  3. 03 · 2 minTurn on the intents
  4. 04 · 3 minInvite it to your server
  5. 05 · 5 minRun it

About 15 minutes the first time. Steps 1 to 4 are the same for everyone. Step 5 depends on what you built.

Before you start

  • The zip from your build, unzipped somewhere you can find again. No project yet? Build one first, the first one is free.
  • A Discord account, and the Manage Server permission on the server you want the bot in. If it is not your server, the owner has to do step 4.
  • For a normal bot, Node.js 18 or newer. Check with node -v in a terminal. If that prints an error rather than a version, install Node first.
  • For a FiveM resource, access to your server files and to server.cfg.
One rule for the whole page. The bot token is a password. It is not a user id, it is not the application id, and anyone who has it owns your bot. Never paste it into a screenshot, a support channel or a public repository. If you do, reset it, which takes ten seconds and is not a big deal.

Steps 1 to 4 happen on discord.com/developers/applications. Discord rearranges that page from time to time, so the labels below matter more than the exact position. Nothing here costs anything.

Create the application

1 min

Open the Developer Portal and press New Application in the top right. Give it a name and accept the terms.

The name is what people will see in the member list, so use the bot's name rather than your own. You can change it later.

You should see. A page with your application's name at the top and a menu down the left side containing General Information, OAuth2 and Bot.

Get the token

1 min

Open Bot in the left menu. Find Reset Token and press it. Discord will ask you to confirm, and may ask for your password or a two factor code.

A long string appears. This is shown once. Copy it now and paste it straight into the place it belongs, which is step 5. If you lose it, press Reset Token again and use the new one. There is no way to look up the old one, by design.

If a guide tells you to look for the token under a Copy button without resetting, that guide is old. Discord stopped showing existing tokens years ago.
You should see. A long string on your clipboard, letters and numbers with two dots in it. That is the token.

Turn on the intents it needs

2 min

Stay on the Bot page and scroll down to Privileged Gateway Intents. There are three switches, and the rule for all three is the same: on only if your bot actually uses it.

Message Content
The bot reads what people write in ordinary messages.
Server Members
The bot reacts to people joining or leaving, or reads the member list.
Presence
The bot cares who is online. Most do not.

Open the README in your project and turn on exactly the ones it lists. Every intent you enable is data Discord sends you and a claim about what the bot does, and past a hundred servers Discord reviews those claims. Slash commands need none of the three, so for many bots you change nothing here at all.

Press Save Changes. The bar at the bottom of the page has to disappear, or nothing was saved.

You should see. The switches your README asked for are green, and the unsaved changes bar is gone.

Invite it to your server

3 min

Open OAuth2 in the left menu, then URL Generator. In the Scopes box, tick two things:

  • bot, which lets it join at all
  • applications.commands, which lets it have slash commands
Forgetting the second one is the single most common mistake on this whole page, and it fails in a way that looks like your code is broken: the bot joins, shows as online, and none of its commands exist. If that happens to you later, come back here.

A Bot Permissions box appears underneath. Tick what the bot actually needs. A moderation bot needs the moderation permissions, a bot that only answers questions needs almost nothing. If you are unsure, start small: you can change the bot's permissions in your server later without re-inviting it.

Copy the link at the bottom, open it in a new tab, pick your server from the dropdown and confirm.

You should see. The bot in your server's member list, greyed out and offline. Offline is correct. Nothing is running yet.

Run it

5 min

This is where the two kinds of project part ways. Pick the one you built. Not sure? Look inside the folder: a fxmanifest.lua means it is a FiveM resource, and no such file means it is a normal Node bot.

A normal Node bot

5.1

Install the dependencies

Open a terminal in the project folder, the one containing package.json, and run:

npm install
You should see. A node_modules folder. Warnings during install are normal. Red text saying ERR! is not.
5.2

Fill in .env

The project contains .env.example, which lists every value the code reads. Copy it to a file named exactly .env:

cp .env.example .env      # macOS and Linux
copy .env.example .env    # Windows

Open it in any text editor and fill in every line. Paste each value after the equals sign, with no quotes and no spaces around it:

TOKEN=paste-the-token-here
CLIENT_ID=your-application-id
GUILD_ID=your-server-id

Your file may name the first one TOKEN or DISCORD_TOKEN. Use whatever your own .env.example lists, do not rename it.

The two that catch people out. CLIENT_ID is the application id, not the token and not the bot's user id. It is on the General Information page of the portal, labelled Application ID. And GUILD_ID is your server's id.

Any id from Discord comes the same way: turn on Developer Mode under Settings, Advanced, then right click the server, channel or role and choose Copy ID. Ids are long numbers, nothing else.

You should see. .env next to package.json, with no value left empty.
5.3

Build it

npm run build
You should see. A dist folder, and the command ended without listing errors.
5.4

Register the commands

Slash commands are registered with Discord separately from the code that answers them. This is a one time step, repeated whenever you add, rename or remove a command.

npm run deploy
You should see. It prints how many commands it registered, and typing a slash in your server shows them.
5.5

Start it

npm start
You should see. One line in the console naming your bot, and the bot turning from grey to online in the member list. Try a command.
5.6

Keep it online

Closing the terminal stops the bot. That is not a bug, it is what a running program is. The thing to understand about the obvious free options: a Discord bot holds one long lived connection and otherwise looks completely idle, and most free tiers sleep anything that looks idle.

  • Your own machine. Fine for building and testing, online exactly as long as the terminal is open.
  • A small always-on server. What most people end up on. A few dollars a month, or free on the tiers that hand you a real machine rather than a sleeping web service. Use a process manager so it restarts itself after a crash or a reboot.
  • A managed platform. Connect a repository and it builds and runs the project for you. The least work, and the place to check the sleeping question first.
Wherever it lands, put the token in that host's environment variable settings rather than uploading your .env file, and never push it to the repository you are deploying from.

When it does not work

Nearly every failure at this stage is one of these, and none of them mean the code is wrong. Find your symptom and open it.

An invalid token was provided+

The token in your config is not the current one. Resetting a token in the portal kills the old one instantly, and Discord also kills any token it finds in a public repository, usually within minutes of the push.

Fix. Reset the token in the portal, paste the new one, and never commit it. If you pushed one to GitHub, reset it before doing anything else.

Used disallowed intents+

Your code asks for a privileged intent that is switched off for your application. The gateway refuses the whole connection rather than the one intent.

Fix. Portal, Bot, Privileged Gateway Intents. Turn on the ones your README lists, then Save Changes. Start the bot again.

The bot is online but the slash commands do not appear+

Almost always the invite link was missing the applications.commands scope. The bot can sit in the server and still have no permission to own commands there.

Fix. Generate a new invite link with both bot and applications.commands ticked, open it, and pick the same server. Then press Ctrl R in the Discord app to drop its cache.

The application did not respond+

A command took longer than three seconds to acknowledge. The interaction token dies at three seconds and there is no second chance.

Fix. This one is handled for you: generated handlers defer first and edit the reply afterwards. If you added a command by hand, do the same.

Commands registered but only in one server+

Guild commands appear instantly and only in the guild you named. Global commands reach everywhere but can take up to an hour.

Fix. Normal while testing. Set the guild id for instant updates, clear it for a real release and wait.

The bot goes offline after a while on a free hostNode+

Most free tiers sleep an idle process. A Discord bot holds a permanent gateway connection, so sleeping it means going offline.

Fix. Use a host that does not sleep. See the hosting section in step 5.

Still stuck? The report button on any page reaches us with the page you were on attached, which is faster than describing it.

Frequently Asked Questions

Discord Developer Portal, New Application, then the Bot tab, then Reset Token. The token is shown once. Copy it straight into your config and close the page.

Treat it exactly like a password. Anyone holding it controls the bot. If you ever paste it into a public repository, a screenshot or a support channel, reset it immediately, because Discord scans public code and will invalidate it anyway.

Intents tell Discord which categories of event to send you. Three of them are privileged and off by default: Message Content, Server Members and Presence.

You need one only if your bot actually uses it. Reading the text of ordinary messages needs Message Content. Reacting to people joining or leaving needs Server Members. Slash commands need none of the three. The README in your generated project lists the ones your particular bot asks for.

The usual reason is that the invite link did not include the applications.commands scope, so the bot is in the server but cannot own commands there. Re-invite it with both scopes ticked.

The second reason is timing: global commands can take up to an hour to appear everywhere, while guild commands appear instantly. The third is your own Discord client caching the old list, which Ctrl R fixes.

For a normal Node bot, yes, unless you put it somewhere else. The bot holds an open connection to Discord and is offline whenever that process is not running.

A FiveM resource is different. It runs inside the server you already pay for, starts when the server starts and needs no separate hosting at all.

For testing, yes. For a bot people rely on, be careful: most free tiers sleep a process that looks idle, and a bot holding a gateway connection looks idle to them, so it drops offline.

The free tiers that genuinely stay up are the ones giving you a real always-on machine rather than a sleeping web service. Otherwise the smallest paid instance anywhere is a few dollars a month.

Not in a .env file. FiveM uses convars, so it goes in your server.cfg as set discord_bot_token "your-token", and the resource reads it at startup.

Put that line above the ensure line for the resource. If your server.cfg is in a public repository or shared with anyone, keep the token in a separate cfg file that you exec and do not share.

Two signs, both in the console rather than in Discord. The bot prints one line naming itself when it connects, and the member list in your server shows it as online.

For a FiveM resource the same line goes to the server console, so watch the console right after the resource starts rather than looking at Discord first.

For a Node bot: npm run build, then start it again. If you added, removed or renamed a command, also run npm run deploy, because the list Discord shows is registered separately from the code that answers.

For a FiveM resource: restart the resource. If you changed the commands, the deploy step still applies.

Do not have the code yet?

Describe what the bot should do and you get the project this guide sets up. The first build is free.