Sharkord
Plugins

Settings

Typed options an admin can edit in the interface.

Register settings and they show up on your plugin's page in the server settings, where an admin can change them without touching code. Values are stored in the database and survive restarts. They are server-wide, not per user: see userData for that.

Register

import type { PluginContext } from "@sharkord/plugin-sdk";

const onLoad = async (ctx: PluginContext) => {
  const settings = await ctx.settings.register([
    {
      key: "welcome-enabled",
      name: "Enable welcome messages",
      description: "Send a message when a user joins the server.",
      type: "boolean",
      defaultValue: true,
    },
    {
      key: "apiKey",
      name: "API key",
      type: "secret",
      defaultValue: "",
    },
    {
      key: "mode",
      name: "Mode",
      type: "enum",
      defaultValue: "fast",
      options: [
        { value: "fast", label: "Fast" },
        { value: "thorough", label: "Thorough" },
      ],
    },
  ] as const);

  const enabled = settings.get("welcome-enabled"); // boolean
  settings.set("welcome-enabled", false);
};

register is async: it reads the stored values, fills in defaults for keys it has not seen, writes them back, and hands you a typed accessor. Call it once, in onLoad, and keep the returned object.

Keep the `as const`

Without it the definitions widen to string, and settings.get loses both the checked key names and the type of what it returns.

Types

TypeRenders asNotes
stringText field
numberNumber field
booleanToggle
secretPassword fieldWrite-only: never sent back to the client
enumSelectRequires options: [{ value, label }]

A definition takes key, name, type, defaultValue, an optional description, and options for an enum. key is how you read the value back and how it is stored, so keep it stable across versions.

secret is the type for API keys and tokens. An admin can replace one but not read it back, and the value never leaves the server. Your plugin reads it normally with get.

Reading and Writing

get and set are synchronous. get reads the value from memory and always returns something, since a key an admin never saved falls back to its defaultValue. set updates it and persists in the background, so there is nothing to await.

const channelId = settings.get("welcome-channel-id"); // number
settings.set("welcome-channel-id", 42);

set on a key you never registered, or with a value of the wrong type, is ignored and logged as an error in the plugin's log.

Reacting to Changes

An admin editing a value in the interface does not go through your set, so watch the event instead:

ctx.events.on("setting:set", ({ key, value }) => {
  if (key !== "welcome-enabled") return;

  ctx.logger.log("welcome messages are now", value);
});

The event is scoped to your own plugin, so you never see another plugin's settings, but you do see your own writes as well as an admin's.

Notes

  • Values written from the interface are validated against your definition: a number setting cannot be set to a string, and an enum cannot be set to a value outside its options.
  • Settings are cleared from memory when the plugin unloads and reloaded from the database on the next register. The stored values are not deleted when a plugin is disabled, only when it is removed.
  • Anything an admin can read in the interface is not a secret from admins. secret settings are hidden from the form, but a plugin running in the server process can do whatever it likes with them. See Security.

On this page