KV Storage
Every TMA.sh project includes a key-value store. No database setup, no connection strings — import the SDK and start reading and writing data.
Client-side API
Section titled “Client-side API”import { createTMA } from '@tma.sh/sdk';
const tma = createTMA({ projectId: 'your-project-id' });Set a value
Section titled “Set a value”Store any JSON-serializable value:
await tma.kv.set('user:123:preferences', { theme: 'dark', language: 'en', notifications: true,});Setting a key that already exists overwrites the previous value.
Get a value
Section titled “Get a value”Retrieve a value by key. Returns null if the key does not exist:
const prefs = await tma.kv.get('user:123:preferences');// { theme: 'dark', language: 'en', notifications: true }Remove a value
Section titled “Remove a value”Remove a key and its value:
await tma.kv.remove('user:123:preferences');Removing a key that does not exist is a no-op.
List keys by prefix
Section titled “List keys by prefix”Retrieve all keys matching a prefix:
const result = await tma.kv.list('user:123:');const keyNames = result.keys.map(k => k.name);// ['user:123:preferences', 'user:123:scores', 'user:123:inventory']The list() method returns an object with keys (an array of { name: string } objects) and list_complete (a boolean indicating whether all matching keys have been returned). Use colons as separators to create a natural key hierarchy. Fetch individual values with kv.get().
Specifications
Section titled “Specifications”| Property | Limit |
|---|---|
| Max value size | 128 KB |
| Max key size | 512 bytes |
| Consistency | Eventually consistent (~60s) |
Values are stored as JSON. The 128 KB limit applies to the serialized JSON string. Keys must be valid UTF-8 strings.
Eventually consistent means that after a write, subsequent reads from different edge locations may return the previous value for up to 60 seconds. Reads from the same location that performed the write are immediately consistent.
Key naming conventions
Section titled “Key naming conventions”Use colon-separated segments for structured keys:
{entity}:{id}:{field}Examples:
user:123:preferencesuser:123:scoresleaderboard:globalsession:abc123feature:dark-modecache:api:weather:londonThis convention makes prefix-based listing predictable and keeps your keyspace organized.
Use cases
Section titled “Use cases”KV storage works well for:
- User preferences — theme, language, notification settings
- Feature flags — toggle features per user or globally
- Leaderboards — store scores keyed by user ID, list by prefix
- Session data — temporary state between page loads
- Cached API responses — store third-party API results with a TTL key pattern
When to use something else
Section titled “When to use something else”KV storage is not a database. For the following use cases, connect an external database like Supabase or Turso instead:
- Relational data — queries that join tables or filter on multiple columns
- Transactions — operations that must succeed or fail atomically
- Complex queries — full-text search, aggregations, sorting by multiple fields
- Strong consistency — reads that must always return the latest write
See the Authentication page for how to connect TMA.sh JWTs to Supabase.
Server-side usage
Section titled “Server-side usage”In API routes, use the createKV() helper from @tma.sh/sdk/server for a typed wrapper around the KV binding. See Server Helpers for details.