User-Level Storage (db.user)¶
Every user gets their own drawer. Alice's credits don't leak into Bob's. Your onboarding step counter doesn't reset when someone else joins. That's db.user — per-user, per-bot storage that actually respects boundaries.
If you need data visible to everyone, that's db.bot. If you need it across all your bots, that's db.global. This page is for the personal stuff.
What is db.user?¶
db.user stores data unique to each user interacting with the bot — profiles, balances, game progress, language preferences, and flow state.
| Property | Value |
|---|---|
| Scope | One user on one bot |
| Isolation | Each user-bot pair has separate data |
| Default context | Current bot + current user.id from the update |
How to use it¶
The happy path — read, write, increment:
let balance = await db.user.incr("credits", 10)
Bot.sendMessage("New balance: " + balance + " credits")
Three things worth knowing upfront:
user_idis auto-filled — for the current user, you rarely need to pass it.incr/decrthrow on failure — unlikeset, which returns{ ok: false }. Different methods, different moods.delis positional only —db.user.del("key", { user_id }), notdb.user.del({ key }).
Methods¶
All unified CRUD methods and advanced operations (incr, decr, push, pull, mget).
Try it — copy-paste examples¶
User balance¶
let balance = await db.user.incr("credits", 10)
Bot.sendMessage("New balance: " + balance + " credits")
Save preference¶
Multi-step flow state¶
await db.user.set("onboard_step", 2)
let step = await db.user.get("onboard_step", 0)
if (step === 2) {
Bot.runCommand("/onboard_step3")
}
Temporary data with TTL¶
OTP codes that expire on their own — because nobody wants a stale verification code haunting their bot forever.
Admin: access another user's data¶
let balance = await db.user.get("credits", 0, { user_id: 123456789 })
await db.user.set("credits", 0, { user_id: 123456789 })
await db.user.del("warned", { user_id: 123456789 })
Object syntax¶
let level = await db.user.get({
key: "level",
fallback: 1,
user_id: 123456789
})
await db.user.set({
key: "referrals",
value: 12,
ttl: 604800,
type: "integer"
})
History log with push/pull¶
await db.user.push("visited_pages", "settings")
await db.user.pull("tags", "inactive")
let pages = await db.user.get("visited_pages", [])
Batch read¶
List all keys for current user¶
Delete one user's data¶
Scoping rules¶
| Operation | Default scope | Override |
|---|---|---|
get, has, mget | Current user | { user_id } in options |
set, del | Current user | { user_id } required for other users |
getAll | Current user | { user_id } in options |
delAll({ user_id }) | One user | Deletes all keys for that user |
delAll() (no user_id) | Entire bot | Deletes all user keys for every user |
delAll without user_id
db.user.delAll() with no user_id wipes all user data for the entire bot. Use only in admin/reset commands. Seriously.
Common use cases¶
- Virtual currency and referral counts (
incr/decr) - Onboarding and wizard step tracking
- User preferences and settings
- Game state and inventory (
push/pullfor lists) - Per-user cooldowns with TTL
Important notes¶
- Replaces deprecated
User.set/User.get— migrate todb.user user_idis auto-filled from the current update — no need to pass it for the active userdelonly accepts positional syntax:db.user.del("key", { user_id })— notdb.user.del({ key })- For bot-wide data, use
db.bot - For cross-bot user bans, use
db.globalwith keys likebanned:{user_id}