
You saw "ephemeral" on a bot reply, an invite setting or a role, or someone asked you to set up ephemeral event channels for a game night. In Discord, ephemeral means temporary, but the word covers several features, and only two of them are real Discord settings. Here is each one, from Discord's own documentation, with discord.js code for the parts that need a bot.
Quick answer: "Ephemeral" in Discord means something that disappears or only lasts a while. It covers ephemeral messages (bot replies to a slash command or button that only you can see, made with the EPHEMERAL message flag, value 64), ephemeral invites (invite links with temporary membership), ephemeral roles (roles a bot gives you while you are in a voice channel and removes when you leave) and ephemeral event channels and voice channels (channels a bot creates for an event or a group and deletes once everyone has left). Discord has no built-in expiring roles or self-deleting channels, so those always come from a bot that stays online.
What "Ephemeral" Means in Discord
| Term | Built into Discord? | What disappears | Who does the work |
|---|---|---|---|
| Ephemeral message | Yes, the EPHEMERAL message flag | A bot reply, visible only to the person who used the command | The bot sets the flag when it answers |
| Ephemeral invite | Yes, "temporary membership" on an invite | The member who joined with the link | Discord removes them |
| Ephemeral role | No | A role tied to a voice channel or a time limit | A bot adds and removes it |
| Ephemeral event channel | Partly: events end on their own, channels stay | The channel created for one event | A bot deletes it when the event ends |
| Ephemeral voice channel | No | A "join to create" voice room | A bot deletes it when it is empty |
The code targets discord.js 14.28.0, the current npm release (30 October 2026), which needs Node.js 18 or newer. Every snippet uses this client; none of its three intents is privileged, so the Developer Portal needs no changes:
// index.js
const {
Client, Events, GatewayIntentBits, MessageFlags, ChannelType,
GuildScheduledEventEntityType, GuildScheduledEventPrivacyLevel,
} = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates, // voice joins and leaves
GatewayIntentBits.GuildScheduledEvents, // event status changes
],
});
client.login(process.env.DISCORD_TOKEN); // keep this line at the bottom of index.js
Ephemeral Messages: Replies Only You Can See
This is what most people mean by ephemeral in Discord. Discord's message documentation defines the EPHEMERAL flag (1 << 6, so 64) as: "this message is only visible to the user who invoked the Interaction". The rules that matter:
- Only interactions can be ephemeral. Slash commands, buttons, select menus and modals give the bot an interaction to answer. A normal channel message cannot carry the flag: Create Message only accepts SUPPRESS_EMBEDS, SUPPRESS_NOTIFICATIONS, IS_VOICE_MESSAGE and IS_COMPONENTS_V2.
- Three seconds to answer. The first response must arrive within 3 seconds. For slow work, defer first.
- The first response decides. "An existing message's ephemeral state cannot be changed." After a deferred response, the first follow-up keeps the choice you made in the defer.
- 15 minutes to follow up. The interaction token is valid for 15 minutes, so edits and follow-ups must happen within that window.
client.once(Events.ClientReady, async (c) => {
// A guild command is available in that server immediately
await c.application.commands.create(
{ name: 'whoami', description: 'Shows your account ID, only to you' },
process.env.GUILD_ID,
);
console.log(`Logged in as ${c.user.tag}`);
});
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand() || interaction.commandName !== 'whoami') return;
await interaction.reply({
content: `You are ${interaction.user.username}, ID ${interaction.user.id}.`,
flags: MessageFlags.Ephemeral,
});
});
For slow work, call await interaction.deferReply({ flags: MessageFlags.Ephemeral }) first and await interaction.editReply('Done.') later. discord.js marks the old ephemeral: true option as deprecated: "Use flags instead."
Registering on every start is fine while testing, since Discord overwrites a command with the same name, but it allows only 200 command creates per guild per day. For production, register once with a deploy script, as in our slash commands guide.
Ephemeral Invite: Links With Temporary Membership
An ephemeral invite has temporary membership turned on. In Discord's API that is the temporary field, "whether this invite only grants temporary membership", off by default. Discord's developer documentation says no more. The libraries describe the effect: discord.py says "members who joined via this invite will be kicked upon disconnect", and discord.js says members are removed if they "have not yet received a role". They differ on timing, so test with a second account before a real event.
Other settings that make a link short-lived, from Discord's Create Channel Invite documentation:
max_age: seconds until expiry, from 0 (never) to 604800 (7 days); default 86400 (24 hours)max_uses: 0 for no limit, otherwise up to 100unique: always create a new code instead of reusing a similar inviterole_ids: roles given to everyone who accepts (the bot needs Manage Roles)
Because discord.js names a role as what keeps a temporary member, test before combining temporary with role_ids.
// channel: any text or voice channel the bot can see
const invite = await channel.createInvite({
temporary: true, // temporary membership
maxAge: 3600, // link expires after 1 hour
maxUses: 25,
unique: true,
reason: 'Guest pass for tonight',
});
console.log(invite.url);
The bot needs the Create Invite permission on that channel.
Ephemeral Roles: Roles That Follow Voice Channels
Discord has no setting that makes a role expire. The term comes from the open source Ephemeral Roles bot (MIT licence, on GitHub): when a member joins a voice channel, it "automatically assigns that member an ephemeral role associated with the channel", creates the role if needed, and revokes or reissues roles when members move or disconnect. When a role is pinned in the member list (the role's hoist setting), Discord shows its members as a separate group, so everyone sees who is in which channel. The bot needs Manage Roles, with its own role near the top of your role list.
The same idea in your own bot:
// Voice channel ID -> role ID
const VOICE_ROLES = new Map([
['123456789012345678', '234567890123456789'],
]);
client.on(Events.VoiceStateUpdate, async (oldState, newState) => {
if (oldState.channelId === newState.channelId) return; // mute, deafen, stream
const member = newState.member;
if (!member) return;
try {
const oldRole = VOICE_ROLES.get(oldState.channelId);
const newRole = VOICE_ROLES.get(newState.channelId);
if (oldRole) await member.roles.remove(oldRole, 'Left voice channel');
if (newRole) await member.roles.add(newRole, 'Joined voice channel');
} catch (err) {
console.error('Role change failed:', err.message);
}
});
Discord's rule: "a bot can grant roles to other users that are of a lower position than its own highest role." If the voice role sits above the bot's role, the call fails with a permissions error. Timed roles, such as a 48 hour trial role, work the same way, but store the expiry in a file or database instead of a setTimeout, because timers vanish on restart.
Ephemeral Event Channels With Scheduled Events
Ephemeral event channels exist for one game night, raid or meeting and are gone afterwards. Discord's scheduled events do half of this. According to Discord's documentation, an active voice channel event "will automatically end a few minutes after the last user leaves the channel", and an event that never started is "automatically cancelled after a few hours". External events start and end on their own at the scheduled times.
Discord does not delete the channel, but a bot can: it creates a voice channel with an event in it, then deletes the channel when the event reaches COMPLETED or CANCELED. Both statuses are final: once set, "the status can no longer be updated".
const eventChannels = new Map(); // event ID -> channel ID
async function createGameNight(guild, startsAt) {
const channel = await guild.channels.create({
name: 'game-night',
type: ChannelType.GuildVoice,
});
const event = await guild.scheduledEvents.create({
name: 'Game night',
scheduledStartTime: startsAt,
privacyLevel: GuildScheduledEventPrivacyLevel.GuildOnly,
entityType: GuildScheduledEventEntityType.Voice,
channel,
});
eventChannels.set(event.id, channel.id);
return event.createInviteURL({ maxAge: 86400 }); // invite link that opens the event
}
async function cleanUp(event) {
const channelId = eventChannels.get(event.id);
if (!channelId) return;
eventChannels.delete(event.id);
const channel = await event.guild.channels.fetch(channelId).catch(() => null);
if (channel) await channel.delete('Event is over');
}
client.on(Events.GuildScheduledEventUpdate, (oldEvent, newEvent) => {
if (newEvent.isCompleted() || newEvent.isCanceled()) cleanUp(newEvent).catch(console.error);
});
client.on(Events.GuildScheduledEventDelete, (event) => cleanUp(event).catch(console.error));
Call createGameNight from a slash command and post the returned link. The bot needs Manage Channels, Create Events and Create Invite, plus View Channel and Connect on the channel, which Discord checks for voice events. This sketch is for one-off events.
Ephemeral Voice Channels: Join to Create
"Discord ephemeral voice" usually means join to create: a member joins a lobby channel, the bot creates a personal room, moves them in and deletes the room once it is empty.
const LOBBY_ID = '345678901234567890'; // your "Join to create" channel
const tempRooms = new Set();
client.on(Events.VoiceStateUpdate, async (oldState, newState) => {
try {
if (newState.channelId === LOBBY_ID && oldState.channelId !== LOBBY_ID && newState.member) {
const room = await newState.guild.channels.create({
name: `${newState.member.displayName}'s room`,
type: ChannelType.GuildVoice,
parent: newState.channel.parentId, // same category as the lobby
});
tempRooms.add(room.id);
// If the member already left the lobby, delete the unused room
await newState.setChannel(room).catch(() => room.delete());
}
const left = oldState.channel;
if (left && tempRooms.has(left.id) && left.members.size === 0) {
tempRooms.delete(left.id);
await left.delete('Temporary room is empty');
}
} catch (err) {
console.error('Temporary room error:', err.message);
}
});
Creating and deleting channels needs Manage Channels. For the move, the bot "must have permissions to both connect to the channel" and have Move Members.
Keep the Bot Online, or Nothing Disappears
All of these bot features run on gateway events: VOICE_STATE_UPDATE for voice roles and rooms, GUILD_SCHEDULED_EVENT_UPDATE for event channels. If the bot is offline when someone leaves, the role and the empty room stay. A restart also wipes the in-memory Map and Set above, so in a real bot store channel IDs and role expiry times in SQLite or a JSON file, and on ClientReady delete stored rooms that are empty and remove voice roles from members who left.
Our Discord bot hosting runs this kind of bot on the Growth plan: 512 MB RAM, no sleep mode, auto-restart after a crash, and Node.js, Python or Java. For the rest of the setup, see how to run a Discord bot around the clock.
Best Practices
- Say that it is temporary in the channel name, topic or event description.
- Keep ephemeral roles small: only the permissions the event needs, with the bot's role just above the roles it hands out.
- Test the removal with a second account: join, leave and restart the bot while someone is in voice.
- Use ephemeral replies for errors, settings and private output. For roles members pick themselves, see our reaction roles guide.
FAQ
What does ephemeral mean in Discord? Temporary. Most often it means an ephemeral message: a bot's reply to your slash command that only you can see. It is also used for invites with temporary membership, roles a bot removes again and channels a bot deletes after use.
What are Discord ephemeral event channels? Channels created for one event and deleted after it. Discord ends a voice channel event a few minutes after the last person leaves but keeps the channel; a bot listening for COMPLETED or CANCELED deletes it.
What is an ephemeral role in Discord? A role a bot gives and removes automatically, usually while a member is in a specific voice channel. The open source Ephemeral Roles bot made the term popular; Discord has no expiring roles.
What is a Discord ephemeral invite?
An invite with temporary membership (temporary: true in the API). Library documentation says members who joined this way are removed unless they receive a role, so test it first. For a link that simply stops working, set an expiry and a use limit.
Can a bot send an ephemeral message without a slash command? Not by itself. The flag only works in responses and follow-ups to interactions: slash commands, buttons, select menus and modals. A message the bot posts on its own is visible to everyone in the channel.
Can I make an ephemeral reply public later? No, an existing message's ephemeral state cannot be changed. Send a new, public follow-up within the 15 minute window instead.
Sources
All opened on 3 November 2026:
- Discord developer documentation: Receiving and responding to interactions, Message resource, Channel resource (Create Channel Invite), Invite resource, Guild resource, Guild scheduled events, Gateway intents, Permissions, Application commands
- discord.js: Guide: command response methods, InteractionReplyOptions (14.28.0), discord.js on npm, invite options in BaseGuildTextChannel.js
- discord.py: invite.py, abc.py (create_invite)
- Ephemeral Roles bot on GitHub