Discord botunuzun kullanıcılarla konuştuğu ana kapı artık slash command, yani sohbet kutusuna / yazınca açılan komut listesidir. Doğru kurgulanmış bir slash komut, kullanıcıdan gelen veriyi daha gönderilmeden doğrular, yanlış kişinin yönetim komutunu görmesini engeller ve DM ya da sunucu gibi hangi ortamda çalışacağını kendisi belirler. Kötü kurgulanmış bir komut ise listede iki kez görünür, hiç görünmez ya da herkesin kullanabildiği bir "ban" komutuna dönüşür.

Bu rehberde Discord'un resmî Application Commands belgesine ve discord.js rehberine dayanarak bir slash komutun bütün parçalarını ele alıyoruz: SlashCommandBuilder, seçenek (option) türleri, zorunlu alanlar ve hazır seçimler, autocomplete, alt komutlar ve gruplar, default_member_permissions, contexts ile integration_types, sunucuya özel ve global kayıt farkı ve sağ tık menüsünde çıkan kullanıcı ile mesaj komutları. Botunuz henüz yoksa önce Discord bot nasıl yapılır yazısıyla temel kurulumu tamamlayın.

Application command türleri

Application command türleri: CHAT_INPUT, USER, MESSAGE, PRIMARY_ENTRY_POINT

Discord'da slash komut, daha geniş bir yapı olan application command'ın bir türüdür. Bir komut nesnesinin type alanı komutun nerede görüneceğini belirler; alan verilmezse varsayılan değer 1 olur.

TürDeğerNerede görünür
CHAT_INPUT1Sohbet kutusuna / yazınca açılan liste (slash command)
USER2Bir kullanıcıya sağ tıklayınca ya da dokununca açılan "Apps" menüsü
MESSAGE3Bir mesaja sağ tıklayınca ya da dokununca açılan "Apps" menüsü
PRIMARY_ENTRY_POINT4Uygulamanın Activity'sini başlatan ana giriş komutu

Komutlar bir bot kullanıcısına bağlı değildir; interaction modeliyle çalışır. Bir sunucuda komut oluşturabilmek için uygulamanın o sunucuda applications.commands kapsamıyla yetkilendirilmiş olması gerekir. Bu kapsam bot kapsamıyla birlikte otomatik gelir. Davet bağlantısının nasıl kurulduğunu bot davet linki rehberinde anlattık.

Adlandırma kuralları ve sınırlar

Komut kaydı reddedildiğinde sebep çoğu zaman bu tablodaki sınırlardan biridir. Değerler resmî belgedeki komut ve seçenek yapısından alınmıştır.

AlanSınır
Komut ve seçenek adı (CHAT_INPUT)1-32 karakter; küçük harf varyantı olan harflerin küçük hâli kullanılmalı; boşluk yok, sembol olarak yalnızca - ve _
USER ve MESSAGE komut adıBüyük harf ve boşluk içerebilir
Açıklama (description)CHAT_INPUT için 1-100 karakter; USER ve MESSAGE komutlarında gönderilemez
Seçenek sayısıKomut başına en fazla 25
Hazır seçim (choices)Seçenek başına en fazla 25; seçim adı 1-100 karakter, string değer en fazla 100 karakter
Toplam metinAd, açıklama ve değerlerin toplamı komut başına en fazla 8000 karakter
Global komut sayısı100 CHAT_INPUT, 15 USER, 15 MESSAGE, 1 PRIMARY_ENTRY_POINT
Sunucu komutu sayısıPRIMARY_ENTRY_POINT dışındaki türlerde her sunucu için aynı sayılar
Oluşturma limitiSunucu başına günde 200 komut oluşturma

SlashCommandBuilder ile ilk komut

discord.js v14'te komut tanımı SlashCommandBuilder ile yazılır ve toJSON() çıktısı Discord'a gönderilir. Aşağıdaki /duyuru komutu zorunlu bir metin, isteğe bağlı bir kanal ve hazır seçimli bir öncelik alanı içeriyor. Ayrıca yalnızca "Sunucuyu Yönet" iznine sahip üyelere ve yalnızca sunucu içinde açılıyor.

javascript
const {
  SlashCommandBuilder, PermissionFlagsBits, InteractionContextType, ChannelType, MessageFlags,
} = require('discord.js');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('duyuru')
    .setDescription('Seçilen kanala duyuru gönderir')
    .addStringOption((o) =>
      o.setName('metin').setDescription('Duyuru metni').setRequired(true).setMaxLength(2000))
    .addChannelOption((o) =>
      o.setName('kanal').setDescription('Hedef kanal').addChannelTypes(ChannelType.GuildText))
    .addStringOption((o) =>
      o.setName('oncelik').setDescription('Öncelik düzeyi').addChoices(
        { name: 'Normal', value: 'normal' },
        { name: 'Acil', value: 'acil' },
      ))
    .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
    .setContexts(InteractionContextType.Guild),

  async execute(interaction) {
    const metin = interaction.options.getString('metin', true);
    const kanal = interaction.options.getChannel('kanal') ?? interaction.channel;
    const oncelik = interaction.options.getString('oncelik') ?? 'normal';
    await kanal.send(oncelik === 'acil' ? `**ACİL:** ${metin}` : metin);
    await interaction.reply({ content: 'Duyuru gönderildi.', flags: MessageFlags.Ephemeral });
  },
};

Seçenek (option) türleri

Her seçenek türünün discord.js'te bir add...Option metodu ve okumak için bir get... metodu vardır. Değerler resmî "Application Command Option Type" tablosundandır.

Tür (değer)Builder metoduOkumaNot
STRING (3)addStringOptiongetStringmin_length / max_length 0-6000 arası
INTEGER (4)addIntegerOptiongetIntegerYalnızca tam sayı; min_value / max_value
BOOLEAN (5)addBooleanOptiongetBooleanEvet / hayır
USER (6)addUserOptiongetUser, getMemberKullanıcı seçici açılır
CHANNEL (7)addChannelOptiongetChannelKategoriler dahil; channel_types ile daraltılır
ROLE (8)addRoleOptiongetRoleRol seçici
MENTIONABLE (9)addMentionableOptiongetMentionableKullanıcı ve rol birlikte
NUMBER (10)addNumberOptiongetNumberOndalıklı sayı
ATTACHMENT (11)addAttachmentOptiongetAttachmentDosya yükletir; file_types ile filtrelenebilir
SUB_COMMAND (1) / SUB_COMMAND_GROUP (2)addSubcommand / addSubcommandGroupgetSubcommand / getSubcommandGroupKomutu dallara ayırır

get... metotlarına ikinci parametre olarak true verirseniz seçenek boş geldiğinde discord.js hata fırlatır; zorunlu seçenekler için bu, null kontrolünü gereksiz kılar.

Zorunlu alanlar, choices ve ek doğrulama

Zorunlu alanlar, choices ve ek doğrulama: setRequired(true), addChoices(), setMinLength / setMaxLength, setMinValue / setMaxValue
  • setRequired(true): Kullanıcı bu alanı doldurmadan komutu gönderemez. Her seçenek türüne uygulanabilir.
  • addChoices(): STRING, INTEGER ve NUMBER seçeneklerinde kullanılır. Belge açıkça söylüyor: choices tanımlarsanız kullanıcının seçebileceği tek geçerli değerler bunlardır.
  • setMinLength / setMaxLength: STRING seçenekleri için uzunluk sınırı.
  • setMinValue / setMaxValue: INTEGER ve NUMBER için aralık sınırı.
  • addChannelTypes(): Kanal seçicide yalnızca belirli kanal türlerini gösterir, örneğin ChannelType.GuildText.
  • file_types: 5 Ağustos 2026 değişiklik kaydından beri ATTACHMENT seçenekleri, image, video, audio ya da .pdf gibi uzantılarla en fazla 10 dosya türüne göre filtrelenebiliyor. Filtre yalnızca dosya uzantısına bakar.

Autocomplete: yazdıkça öneri sunmak

25'ten fazla seçeneğiniz varsa ya da öneriler bir veritabanından geliyorsa sabit choices yerine autocomplete kullanın. Seçeneği setAutocomplete(true) ile işaretlersiniz; kullanıcı yazdıkça Discord botunuza APPLICATION_COMMAND_AUTOCOMPLETE (tür 4) interaction'ı gönderir. Odaktaki seçenek focused: true ile işaretlenir.

javascript
// Komut tanımı
.addStringOption((o) =>
  o.setName('sehir').setDescription('Şehir adı').setAutocomplete(true))

// interactionCreate içinde
if (interaction.isAutocomplete()) {
  const yazilan = interaction.options.getFocused().toLowerCase();
  const sehirler = ['Adana', 'Ankara', 'Antalya', 'Bursa', 'İstanbul', 'İzmir'];
  const sonuc = sehirler
    .filter((s) => s.toLowerCase().startsWith(yazilan))
    .slice(0, 25)
    .map((s) => ({ name: s, value: s }));
  await interaction.respond(sonuc);
}
  • Bir seçenekte hem choices hem autocomplete olamaz.
  • Yanıt en fazla 25 öneri içerebilir; boş dizi gönderirseniz kullanıcı eşleşme olmadığını görür.
  • Autocomplete interaction'ı da 3 saniye içinde yanıtlanmalıdır ve ertelenemez (defer edilemez). Yavaş bir API'den veri çekiyorsanız sonuçları önbelleğe alın.
  • Öneriler zorunlu değildir; kullanıcı listede olmayan bir değer de gönderebilir.
  • Birden çok autocomplete alanı varsa getFocused(true) ile odaktaki seçeneğin adını da alabilirsiniz.

Alt komutlar ve alt komut grupları

/rol ekle, /rol kaldir gibi ilişkili işlemleri tek komut altında toplamak için subcommand kullanılır. Belgeye göre desteklenen tek iç içe yapı şudur: üst komut, alt komut grupları içerebilir ve bu gruplar alt komutlar içerebilir. Grubun içinde grup ya da alt komutun içinde grup kullanılamaz.

javascript
const data = new SlashCommandBuilder()
  .setName('ayar')
  .setDescription('Sunucu ayarları')
  .addSubcommand((s) => s.setName('goster').setDescription('Mevcut ayarları gösterir'))
  .addSubcommandGroup((g) =>
    g.setName('log').setDescription('Log ayarları')
      .addSubcommand((s) =>
        s.setName('kanal').setDescription('Log kanalını belirler')
          .addChannelOption((o) => o.setName('kanal').setDescription('Kanal').setRequired(true)))
      .addSubcommand((s) => s.setName('kapat').setDescription('Logları kapatır')));

// Çalıştırırken
const grup = interaction.options.getSubcommandGroup(false); // 'log' ya da null
const alt = interaction.options.getSubcommand();            // 'goster', 'kanal', 'kapat'

Yetki: default_member_permissions

default_member_permissions alanı, komutu kullanabilmek için üyenin sahip olması gereken izinleri bit dizisi (bitfield) olarak taşır. discord.js'te setDefaultMemberPermissions() ile ayarlanır. Birden fazla izin | ile birleştirilirse üyenin hepsine sahip olması gerekir; "şu izinlerden biri yeterli" diye bir seçenek yoktur.

  • Değeri "0" (discord.js'te 0) yaparsanız komut, özel bir izin tanımlanmadığı sürece yöneticiler dışında herkesten gizlenir.
  • Bu bir varsayılandır. Sunucu yöneticileri "Server Settings" altındaki "Integrations" ekranından komut bazında kullanıcı, rol ve kanal izinlerini değiştirebilir.
  • Administrator iznine sahip üyeler her komutu kullanabilir. Yalnızca geliştiriciye ait eval gibi komutları global dağıtmayın, kendi test sunucunuzla sınırlayın.
  • Komut izinlerini API ile düzenlemek (PUT .../permissions) bot token ile çalışmaz; applications.commands.permissions.update kapsamına sahip bir Bearer token gerekir.

Rol sıralaması ve bot izinlerinin ayrıntısı için Discord bot izinleri ve rol hiyerarşisi yazısına bakabilirsiniz.

contexts ve integration_types: komut nerede çalışır?

contexts ve integration_types: komut nerede çalışır? contexts, integration_types

Eskiden DM'de kullanımı kapatmak için kullanılan dm_permission alanı belgede kullanımdan kaldırılmış (deprecated) olarak işaretli; yerine contexts kullanılıyor. İki alan da yalnızca global komutlarda geçerlidir.

AlanDeğerlerAnlamı
contextsGUILD (0), BOT_DM (1), PRIVATE_CHANNEL (2)Komutun istemcide nerede kullanılabileceği
integration_typesGUILD_INSTALL, USER_INSTALLUygulama sunucuya mı, kullanıcıya mı yüklendiğinde komutun var olacağı

PRIVATE_CHANNEL bağlamı yalnızca kullanıcıya yüklenen komutlar için anlamlıdır, yani komutun integration_types değeri USER_INSTALL içermelidir. Sunucu komutları BOT_DM bağlamını desteklemez. discord.js'te bağlamı setContexts(InteractionContextType.Guild) gibi ayarlarsınız. Kullanıcıya yüklenen uygulamaların ayrıntısı user install rehberinde.

Sunucu (guild) ve global kayıt: ne zaman yeniden kaydetmeli?

Komutlar yalnızca HTTP API ile kaydedilir. İki kapsam vardır ve farkları önemlidir:

Guild komutuGlobal komut
Nerede görünürYalnızca belirtilen sunucudaUygulamanın yüklü olduğu tüm sunucularda (ve bağlama göre DM'de)
GüncellemeBelgeye göre anındaRead-repair: eski sürüm kullanılırsa Discord reddedip yeniler
Önerilen kullanımGeliştirme ve testYayına hazır komutlar
Uç nokta/applications/{id}/guilds/{guild_id}/commands/applications/{id}/commands

discord.js rehberinin önerdiği yöntem, komutları botu başlatan koddan ayrı, küçük bir deploy-commands.js betiğiyle kaydetmektir:

javascript
const { REST, Routes } = require('discord.js');
const komutlar = [require('./commands/duyuru').data.toJSON()];

const rest = new REST().setToken(process.env.DISCORD_TOKEN);

(async () => {
  // Test sunucusu: anında görünür
  await rest.put(
    Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID),
    { body: komutlar },
  );
  // Yayına alırken global:
  // await rest.put(Routes.applicationCommands(process.env.CLIENT_ID), { body: komutlar });
  console.log('Komutlar kaydedildi');
})();
  • Ne zaman çalıştırılır: Yalnızca komutun tanımı (ad, açıklama, seçenekler, izinler) değiştiğinde. execute fonksiyonundaki kod değişiklikleri için yeniden kayıt gerekmez.
  • Her açılışta kaydetmeyin: Günlük oluşturma limiti olduğu için kaydı ready olayına koymak önerilmez.
  • PUT dikkat: Bulk overwrite (PUT) o kapsamdaki tüm komut türlerinin listesini değiştirir; slash, user ve message komutlarının hepsini aynı dizide göndermelisiniz. Var olmayan komutlar günlük oluşturma limitine sayılır.
  • POST bir upsert'tür: Aynı adla yeni komut göndermek mevcut komutu günceller.
  • Silmek: Tek komut için DELETE uç noktası, bir kapsamın tamamı için boş dizi ile PUT kullanılır.

Token ve ID'leri koda yazmak yerine .env dosyasında tutun; neden önemli olduğunu bot token güvenliği yazısında anlattık.

Kullanıcı ve mesaj komutları (context menu)

USER ve MESSAGE komutları sağ tık menüsünde "Apps" altında görünür. Argüman almazlar; Discord tıklanan kullanıcıyı ya da mesajı interaction ile birlikte gönderir. Açıklama alanı gönderilemez (okurken boş string döner) ve alt komut ya da seçenek eklenemez.

javascript
const { ContextMenuCommandBuilder, ApplicationCommandType, MessageFlags } = require('discord.js');

const profil = new ContextMenuCommandBuilder()
  .setName('Profili Göster')
  .setType(ApplicationCommandType.User);

const sikayet = new ContextMenuCommandBuilder()
  .setName('Mesajı Bildir')
  .setType(ApplicationCommandType.Message);

// interactionCreate içinde
if (interaction.isUserContextMenuCommand()) {
  await interaction.reply({ content: `Seçilen kullanıcı: ${interaction.targetUser.username}`, flags: MessageFlags.Ephemeral });
} else if (interaction.isMessageContextMenuCommand()) {
  await interaction.reply({ content: `Bildirilen mesaj: ${interaction.targetMessage.url}`, flags: MessageFlags.Ephemeral });
}

Bu iki komut da aynı kayıt betiğiyle, toJSON() çıktısı aynı diziye eklenerek kaydedilir. Belgeye göre bir kullanıcı komutunu çalıştırmak için kullanıcının o kanalda mesaj gönderme iznine sahip olması gerekir; aksi hâlde "Permission Denied" hatası alır.

Komutları tek yerden karşılamak

Tüm komut türleri Events.InteractionCreate olayına düşer. Basit bir yönlendirici şöyle görünebilir:

javascript
client.on(Events.InteractionCreate, async (interaction) => {
  if (interaction.isChatInputCommand()) {
    const komut = client.commands.get(interaction.commandName);
    if (!komut) return;
    try {
      await komut.execute(interaction);
    } catch (hata) {
      console.error(hata);
    }
  } else if (interaction.isAutocomplete()) {
    const komut = client.commands.get(interaction.commandName);
    await komut?.autocomplete?.(interaction);
  }
});

Komut 3 saniyeden uzun sürüyorsa kullanıcı "Etkileşim başarısız oldu" uyarısı görür. Bunun çözümünü etkileşim başarısız oldu hatası yazısında ayrıntılı anlattık. Komut yanıtına buton veya menü eklemek için buton, select menu ve modal rehberine geçebilirsiniz.

Sık Sorulan Sorular

Komutum listede görünmüyor, neden?

En sık sebepler: kayıt betiği hiç çalıştırılmadı ya da hata verdi, uygulama o sunucuda applications.commands kapsamıyla eklenmedi, komut default_member_permissions ile sizden gizlendi ya da contexts o ortamı kapsamıyor. Belgeye göre bir komutu kullanma izniniz yoksa komut seçicide görünmez. Test ederken guild kaydı kullanın; belgeye göre guild komutları anında güncellenir.

Komutlarım listede iki kez görünüyor

Aynı adlı bir komutu hem global hem guild olarak kaydettiyseniz ikisi de görünür; belge bu ikiliye açıkça izin veriyor. Test bittiğinde guild komutlarını boş dizi ile PUT ederek temizleyin. discord.js rehberi geliştirme için ayrı bir test uygulaması kullanmayı da öneriyor.

Yönetici olmayanlardan komutu tamamen gizleyebilir miyim?

setDefaultMemberPermissions(0) ile komut yöneticiler dışında herkesten gizlenir. Ancak Administrator iznine sahip üyelerin bir komutu kullanmasını engellemek mümkün değildir.

Türkçe komut adı kullanabilir miyim?

Ad kuralı Unicode harflere izin veriyor, ancak küçük harf varyantı olan harflerin küçük hâli kullanılmalı. Daha güvenli yol, adı ASCII tutup setNameLocalizations() ve setDescriptionLocalizations() ile Türkçe (tr) yerelleştirme eklemektir.

discord.py ile de aynı şeyler yapılabilir mi?

Evet. Kavramlar API seviyesinde aynıdır; discord.py 2.x'te komutlar app_commands ve bir CommandTree ile tanımlanıp tree.sync() ile kaydedilir. Ayrıntılar için discord.py ile bot yapımı yazısına bakın.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Discord bot nasıl yapılır · Etkileşim başarısız oldu hatası · Buton, select menu ve modal · User install uygulamalar · Bot izinleri ve rol hiyerarşisi · Discord bot kütüphaneleri karşılaştırma · Node.js nedir