BuildSDK 0.10.1

Sandboxed SQL

These docs are public. To publish a plugin you need a YourBot account: sign in to open the Dev Portal.

For relational data heavier than KV. Each (plugin, server) pair gets its own isolated Postgres schema: your tables for server A and server B are physically separate, so you never need a server_id column and cannot query across servers. Capability: storage:sql — servers consent to it at install time, and it lands in the normal staff review every new developer's submissions go through.

ctx.sql.execute(
    "CREATE TABLE IF NOT EXISTS scores ("
    "  user_id TEXT PRIMARY KEY,"
    "  points  INT NOT NULL DEFAULT 0)"
)

ctx.sql.execute(
    "INSERT INTO scores (user_id, points) VALUES (%s, %s) "
    "ON CONFLICT (user_id) DO UPDATE SET points = scores.points + EXCLUDED.points",
    ["user_42", 5],
)

rows  = ctx.sql.query("SELECT * FROM scores ORDER BY points DESC LIMIT 10")
top   = ctx.sql.query_one("SELECT * FROM scores WHERE user_id = %s", ["user_42"])
total = ctx.sql.scalar("SELECT COUNT(*) FROM scores")

Use %s placeholders (psycopg style); ? and $1 are not accepted. Never build SQL with f-strings or concatenation: it is injection-prone, the upload scan flags it and it will fail review. Queries return at most 1000 rows (hard cap; limit=N only fetches fewer) and the cut is silent — ctx.sql.query returns just the rows, so page with LIMIT/OFFSET or run a COUNT(*) first when the table can outgrow the cap. One statement per call from an allowlist (SELECT, INSERT, UPDATE, DELETE, CREATE/ALTER/DROP TABLE, CREATE/DROP INDEX), each with a 5-second execution timeout. Table names must be unqualified — your own tables only, no schema prefixes and no pg_catalog / information_schema. Quotas: 100 tables and 10,000,000 rows per (plugin, server), and schema-changing DDL is limited to 20 statements/hour (idempotent IF NOT EXISTS re-runs are exempt).

YourBot docs Reference tables are generated from the code that is running. Ask in Discord Suggest a correction