How to Make a Discord Bot with discord.js or Python
Quick answer
To make a Discord bot, create an application in the Discord Developer Portal, generate a token on the Bot page, and add the bot to your server with an invite link that includes the bot and applications.commands scopes. Then install discord.js v14 for JavaScript or discord.py 2.x for Python and write a short script that reads the token from an environment variable. Use slash commands rather than prefix commands for new bots; you only need the Message Content intent if you really must read message text.
What do you need to make a Discord bot?
You need a Discord account, a test server where you have admin rights and a programming language. The two most common choices are discord.js for JavaScript and discord.py for Python. At the time of writing, discord.js is on major version 14 and discord.py on the 2.x series. Both cover the whole Discord API, so pick the language you are more comfortable in.
For discord.js, install a current LTS release of Node.js; for discord.py, a current Python 3. An editor such as Visual Studio Code is plenty. You can run the bot on your own computer while you build it and move it to a server once you want it online all the time; the last section touches on that.
- A Discord account and a test server where you have Manage Server
- Node.js (current LTS) and npm for discord.js
- Python 3 and pip for discord.py
- A code editor and a terminal
- Git for your code, never with the token committed
How do you create a bot in the Discord Developer Portal?
Sign in at discord.com/developers/applications and click New Application. The application is your bot's identity on Discord: its name, icon and description live here. Copy the Application ID from the General Information page, because you need it when registering commands.
Open the Bot page from the sidebar. Here you set the bot's username and avatar and generate its token with Reset Token. The token is shown only once, so copy it somewhere safe straight away. If you do not want other people inviting your bot, switch off Public Bot on the same page so only you can use the invite link.
The token is your bot's password. Anyone holding it can make the bot do anything in every server it belongs to. Never put it in a source file, never show it in a screenshot and never paste it into a help request. If it leaks, click Reset Token immediately; the old token stops working the moment you do.
What are privileged gateway intents and which ones should you enable?
Intents tell Discord which events your bot wants to receive. Most are freely available, but three are privileged and must also be switched on in the Bot page: Presence, Server Members and Message Content. If your code asks for a privileged intent that is disabled in the portal, the bot fails to connect.
Enable only the intents you actually use. A bot that works purely through slash commands needs none of the privileged ones. Once a bot reaches 100 servers it has to be verified, and privileged intents then require an application explaining why you need them; a bot designed around few intents gets through that much more easily. Our guide on keeping a Discord bot online 24/7 covers how intents affect hosting and resource use.
| Privileged intent | What it unlocks | When you need it |
|---|---|---|
| Message Content | Reading message text, attachments and embeds | Prefix commands, message filters, auto-moderation |
| Server Members | Member join and leave events and the full member list | Welcome messages, auto-roles |
| Presence | Members' online status and activity | Status-tracking bots; unnecessary for most |
How do you invite a bot to your server?
You add the bot with an OAuth2 invite link. In the Developer Portal, go to OAuth2, open the URL Generator and tick the bot and applications.commands scopes. The bot scope adds the bot to a server as a member, while applications.commands lets it register slash commands. The Installation page in the portal also gives you a ready-made install link for the same purpose.
Ticking the bot scope opens a list of permissions. Choose only what the bot needs: View Channels, Send Messages and Embed Links cover most bots that post messages. Administrator is tempting, but if the token leaks it hands an attacker your entire server. Open the generated link in a browser, pick your test server, and the bot appears offline in the member list until your code runs.
- Scopes: bot and applications.commands
- Basic permissions: View Channels, Send Messages, Embed Links
- For moderation bots, Manage Messages, Kick Members or Ban Members as needed
- Grant Administrator only if the bot truly needs it
- Link format: discord.com/oauth2/authorize?client_id=APP_ID&scope=bot+applications.commands&permissions=PERMISSION_INTEGER
How do you write a simple bot with discord.js v14?
In an empty folder run npm init -y and then npm install discord.js. The code below is the smallest working bot: it connects with only the Guilds intent and replies Pong! to /ping. It reads the token from an environment variable called DISCORD_TOKEN rather than from the code. Save it as index.js.
Slash commands must be registered with Discord before they work. A common approach is a small separate script: define the command with SlashCommandBuilder and send it with the REST client to Routes.applicationGuildCommands(appId, guildId). Guild commands show up instantly, so use them during development, then register global commands with Routes.applicationCommands(appId) when the bot is ready. Start the bot with node --env-file=.env index.js.
- const { Client, Events, GatewayIntentBits } = require('discord.js');
- const client = new Client({ intents: [GatewayIntentBits.Guilds] });
- client.once(Events.ClientReady, (c) => console.log(`${c.user.tag} is ready`));
- client.on(Events.InteractionCreate, async (i) => { if (i.isChatInputCommand() && i.commandName === 'ping') await i.reply('Pong!'); });
- client.login(process.env.DISCORD_TOKEN);
How do you write a simple bot with discord.py 2.x?
Create a virtual environment (python -m venv .venv), activate it and install the library with pip install -U discord.py. In discord.py, slash commands are defined with the app_commands module and collected on a CommandTree. The example below does the same job as the discord.js one: it connects with the default intents, answers /ping and reads the token from an environment variable.
Calling tree.sync() sends the command tree to Discord. For simplicity the example syncs to a single test server inside on_ready. In a real project, sync only when your commands change rather than on every start, because that endpoint has tight rate limits. Save the file as bot.py and run python bot.py.
- import os, discord; from discord import app_commands
- GUILD = discord.Object(id=123456789012345678) # your test server ID
- client = discord.Client(intents=discord.Intents.default()); tree = app_commands.CommandTree(client)
- @tree.command(name='ping', description='Checks that the bot responds', guild=GUILD)
- async def ping(interaction: discord.Interaction): await interaction.response.send_message('Pong!')
- @client.event, then on the next line: async def on_ready(): await tree.sync(guild=GUILD)
- client.run(os.environ['DISCORD_TOKEN'])
Should you use slash commands or prefix commands?
Slash commands are Discord's built-in command system. Typing / lists your bot's commands with their descriptions, options are validated by type (user, channel, number, choice list), and server admins can manage permissions per command in the server settings. Crucially, they do not need the Message Content intent. For a new bot, slash commands should be the default.
Prefix commands such as !help rely on the bot reading every message and checking the first character, so they need Message Content. They survive in older bots and quick admin tools, and discord.py's commands extension offers hybrid commands that work both ways. Slash commands have one rule to remember: you must respond to an interaction within 3 seconds. For slow work, defer first with deferReply (interaction.response.defer in discord.py) and send the result afterwards.
| Feature | Slash command | Prefix command |
|---|---|---|
| Message Content intent | Not needed | Required |
| Discoverability | Listed when users type / | Users must memorise them |
| Option validation | Done by Discord, by type | Done by hand in code |
| Permissions | Per command in server settings | Done by hand in code |
| Response time | Reply or defer within 3 seconds | No limit |
How do you store a bot token safely?
Keep the token in an environment variable. In practice that means a .env file in the project folder containing DISCORD_TOKEN=... and an entry for .env in .gitignore. Recent Node.js versions read the file themselves with --env-file; in Python, the python-dotenv package does the same. On a server, you set the variable in the hosting panel's environment settings or in your process manager's config.
Tokens pushed to GitHub are found by scanning bots within minutes and used to hijack the bot for spam or mass bans. Discord can automatically reset tokens found in public repositories, but do not rely on that. Before your first push, run git status and make sure .env is not listed. If a token ever made it into a past commit, deleting the file is not enough: reset the token in the portal.
How do Discord API rate limits work?
Discord limits how often a bot can call the API. Each route (sending messages, adding roles, editing channels and so on) has its own limit, and on top of that there is a global limit of 50 requests per second per bot. A request over the limit gets a 429 response that says how long to wait. discord.js and discord.py handle these waits for you, so normal use needs no extra code.
Trouble usually comes from design mistakes: sending hundreds of messages in a loop, assigning roles to every member one by one, or retrying a failing request without waiting. IP addresses that send large numbers of invalid requests (401, 403, 429) in a short time are temporarily blocked by Discord. Pace bulk jobs, combine output into fewer messages where you can, and do not retry requests that failed on permissions.
How do you keep the bot running 24/7?
Your bot is online only while the process running it is alive; shut your computer down and the bot goes with it. For permanent uptime you move the code to an always-on server and use a process manager that restarts it after crashes. Our guide on keeping a Discord bot online 24/7 covers that in detail, including the limits of free platforms and setting up pm2 or systemd.
In short there are two routes: a bot hosting plan with Node.js or Python ready to go, or a VPS where you set everything up yourself. With TheCrewHost's Discord bot hosting you upload your files through the panel and start the bot with a button; if you run several bots or a database alongside them, a VPS gives you more room. An Istanbul location matters less for the Discord connection itself, but it cuts latency for any web dashboard or API your bot serves to users in Türkiye.
Get your first Discord bot running in 8 steps
- 1
Create the application
Open the Discord Developer Portal, click New Application and note the Application ID.
- 2
Get the token
On the Bot page, use Reset Token, copy the token and save it as DISCORD_TOKEN in a .env file in your project folder.
- 3
Set intents
Leave privileged intents off if you only use slash commands; switch on the specific one you need for prefix commands or member events.
- 4
Invite the bot
In the OAuth2 URL Generator, tick the bot and applications.commands scopes plus the permissions you need, and add the bot to your test server.
- 5
Install the library
Run npm install discord.js for JavaScript, or pip install -U discord.py inside a virtual environment for Python.
- 6
Write the code
Write the minimal bot that reads the token from the environment and answers /ping, and add .env to .gitignore.
- 7
Register commands and start
Register the slash commands on your test server, start the bot and type /ping in the server to check the reply.
- 8
Move it to a server
When the bot is ready, upload it to a bot hosting plan or a VPS and keep it running 24/7 with a process manager.
Frequently Asked Questions
Which language is better for a Discord bot?
Both do the same job, so the choice mostly comes down to habit. discord.js has a large community and a detailed guide, and feels natural if you already do web development. discord.py has very readable syntax that suits beginners and works well with Python's data libraries. If you already know one of the two languages, start there; the concepts are almost identical across both libraries.
My bot shows up in the server but stays offline. Why?
The invite link adds the bot as a member, but it only goes online while your code is running and connected to Discord. Check the terminal for errors: an invalid token, a privileged intent requested in code but disabled in the portal, or a network problem are the usual causes. If you reset the token, remember to update the value in your .env file as well.
Why don't my slash commands appear?
The commands must be registered with Discord and the bot must have been invited with the applications.commands scope. Guild commands appear straight away, while global commands can take a little longer to show up. If they are still missing, reload the Discord client with Ctrl+R and confirm your registration script ran without errors. Also check that Use Application Commands is not denied in the channel permissions.
Does it cost anything to make a Discord bot?
No. Creating an application and a bot in the Developer Portal is free, and so are discord.js and discord.py. The only part that costs money is a server to keep the bot online around the clock. You can run the bot on your own machine while developing and move it to a small bot hosting plan or a VPS when it is ready. A small bot uses very few resources.
Can my bot read messages without the Message Content intent?
Partly. With the intent off, the bot still receives message events, but the content, attachments and embeds arrive empty. There are exceptions: messages that mention the bot, direct messages sent to the bot and the bot's own messages still include their content. That is why most bots can drop the intent entirely by switching to slash commands.
Can one bot run in several servers?
Yes. The same invite link can add the bot to as many servers as you like, and one process serves them all. Store per-server settings such as channel IDs, prefixes and roles in a database keyed by server ID. As the bot approaches 100 servers Discord requires verification, and at much larger scale sharding comes into play to split the connection load.
My token leaked. What should I do?
Go to the Bot page in the Developer Portal and click Reset Token right away; the old token stops working instantly and cuts off whoever had it. Put the new token into the environment variable on your server and restart the bot. Then check the server audit log for anything the bot did that you did not intend, and find and fix the way the token escaped.
