On this page
Function Memory
Persistent memory for your Function without setting up a database.
Every newly published MiniUp Function receives env.MINIUP_MEMORY. Memory survives requests, new revisions, and republishing. Existing Functions receive the API when their runtime is refreshed or they are republished. No database credentials or raw SQL are exposed to Function code.
Save and read JSON
export default {
async fetch(request, env) {
if (request.method === "POST") {
const settings = await request.json();
await env.MINIUP_MEMORY.set("settings", settings);
return Response.json({ saved: true });
}
const settings = await env.MINIUP_MEMORY.get("settings");
return Response.json({ settings });
}
};Enable GET and POST for this example. Use MiniUp Users, API Key, or Site Members access for private settings. Memory is shared by callers of the same Function, so your Function must enforce any caller-specific permissions before reading or writing data.
get(key)returns the decoded JSON value, ornullif missing. A stored JSONnullalso returnsnull.set(key, value)creates or replaces JSON data and resolves without a value. It followsJSON.stringifysemantics: dates become strings, object properties containingundefinedare omitted, and non-finite numbers becomenull. Top-levelundefined, functions, symbols, BigInt, and circular values are rejected.delete(key)returns whether a key was removed.list()returns{ keys, cursor }. Each entry containskey,size(JSON bytes),createdAt, andupdatedAt(Unix milliseconds). It does not fetch values. The default page is 100 keys; choose 1–1,000 per page. Pass the returned cursor for the next page.
let cursor;
do {
const page = await env.MINIUP_MEMORY.list({ cursor, limit: 100 });
for (const entry of page.keys) console.log(entry.key, entry.size);
cursor = page.cursor;
} while (cursor);
await env.MINIUP_MEMORY.delete("settings");Isolation and limits
Each Function has its own keys. Other Functions and other owners cannot access them. The Test panel uses separate preview memory; public endpoints use production memory. Testing never reads or modifies production values. Both scopes count toward the same storage quotas.
| Limit | Default |
|---|---|
| Rows per Function, across both scopes | 100 |
| JSON storage per Function | 1,024 KiB |
| Rows per user, across all Functions and scopes | 500 |
| JSON storage per user | 5,120 KiB |
| Key length | 1–128 Unicode characters |
| One JSON value | 64 KiB |
Admins can change the first four limits using the existing default limits and per-user overrides. Production requests receive the current effective limits through their existing authorization check; no redeployment is needed. Preview gets current limits when you click Test (an issued preview expires after five minutes). Lower limits do not erase data. Reads and deletes still work; writes must fit the current limits. Updating an existing key does not consume an extra row. Sizes count UTF-8 JSON value bytes, including JSON punctuation, rather than JavaScript string length or database file size.
Quota checks and writes are atomic. Read–modify–write sequences across separate calls are not atomic; do not use them as reliable concurrent counters. V1 has no increment() or arbitrary SQL access. Catch errors when your Function needs a custom response; errors never include raw database details.
Deleting a Function removes its memory. Admins can inspect keys, view full JSON, delete a key, clear either scope, clear a Function, or clear all Function memory for a user. Destructive actions require confirmation. Failed lifecycle cleanup preserves a retryable Function record.
Related guides
Caller memory
Shared env.MINIUP_MEMORY.get, set, delete, and list continue to work as before. Use env.MINIUP_MEMORY.caller for automatic isolation by authenticated caller. Its methods accept the same arguments and return the same values. Do not ask users for tenant IDs, namespaces, member IDs, or wallet fields to isolate memory. MiniUp determines identity from verified credentials.
env.MINIUP_CALLER is a frozen object containing only { id: "caller_<opaque stable id>", type: "api_key" | "miniup_user" | "site_member" | "x402" }. Its ID is scoped to this Function:
| Request | Caller identity |
|---|---|
| API key | type: "api_key", stable for that key record across renames and secret rotations |
| MiniUp User | type: "miniup_user", stable for that authenticated MiniUp account in this Function |
| Site Member | type: "site_member", stable for the verified member in this Function; existing MINIUP_USER is unchanged |
| Verified x402 payer | type: "x402", stable for the verified network and payer wallet; the raw wallet is not exposed |
| Anonymous public or free x402 route | MINIUP_CALLER is absent |
MiniUp Users, valid API keys, and Site Members that bypass payment retain their authenticated caller identity. The same human can intentionally have separate caller scopes when using the generic MiniUp User path versus a linked Site Member path, because the Site Member path carries application-specific roles. Preview runs have separate memory from production; MiniUp User and Site Member previews use the Function owner as the corresponding preview caller when available.
export default {
async fetch(request, env) {
if (!env.MINIUP_CALLER) {
return Response.json({ error: "Authentication required" }, { status: 401 });
}
const previous = await env.MINIUP_MEMORY.caller.get("last-value");
await env.MINIUP_MEMORY.caller.set("last-value", {
value: 123, updatedAt: Date.now()
});
return Response.json({ caller: env.MINIUP_CALLER.id, previous });
}
};Two callers can store last-value independently. Calling any caller-memory method without an authenticated caller throws Caller-scoped memory requires an authenticated caller. Caller memory consumes the same Function and owner row/byte limits as shared memory, across preview and production. There is currently no separate per-caller quota.
x402 identity is established from verified payment authorization before Function execution. MiniUp preserves settlement after a successful response. If later settlement fails, the caller receives a payment error, but Function execution and memory writes may already have occurred. Verification is not confirmation of settlement; design irreversible business operations accordingly.
Example: isolated customer settings API
For a broad authenticated MiniUp tool, enable MiniUp Users and use MINIUP_MEMORY.caller without creating a users table. Every signed-in MiniUp account receives a distinct caller scope automatically. For a Site-specific app, use the member-preferences handler in Callers and tenants. For an API-key integration, check MINIUP_CALLER and call the direct endpoint with the key.
With two named keys, send different settings to the same endpoint. Each key’s GET returns only its own settings. Use a trusted terminal or server; never embed these keys in your MiniUp site files:
# Set FUNCTION_URL and FUNCTION_API_KEY in your trusted environment.
curl "$FUNCTION_URL" \
-H "Authorization: Bearer $FUNCTION_API_KEY" \
-H "Content-Type: application/json" \
-d '{"theme":"dark"}'
curl "$FUNCTION_URL" -H "Authorization: Bearer $FUNCTION_API_KEY"Page through and remove caller-owned keys
// Inside fetch(request, env), after checking env.MINIUP_CALLER:
const page = await env.MINIUP_MEMORY.caller.list({ limit: 25 });
// Return page.cursor to your client for a subsequent request.
// Supply that cursor to caller.list({ limit: 25, cursor }) next time.
const removed = await env.MINIUP_MEMORY.caller.delete("preferences");
return Response.json({ keys: page.keys, nextCursor: page.cursor, removed });Keep list requests bounded instead of loading every value on each HTTP request. Cursors are opaque; pass them unchanged. Do not use a cursor from another scope or caller. Listing returns metadata, so call get only for the values you need. Deleting a missing key returns false.
Storage design checklist
- Use shared storage only when the data is intended to be shared and the handler enforces any required write permissions.
- Use caller storage for per-key, per-user, or per-member data; its API takes no tenant or caller-ID argument.
- Store small JSON values. Use Tables for queryable records and static files or data files for larger datasets.
- Memory has no automatic TTL API. Store an expiry timestamp and implement any desired expiration policy explicitly.
- A successful write does not make a multi-step operation transactional. Concurrent read–modify–write can lose updates. Use a service with transactions for balances, inventory, or strict counters.
- Production memory remains through draft edits, republishing, key renames, and rotations. Preview values never migrate automatically into production.
- Storage-limit errors do not imply that existing data was deleted. Reduce stored data or ask the administrator to review your limits, then retry deliberately.
Administrators can expand Function Memory below the Function catalog, search by user or Function, open a Function’s keys, and inspect preview/production and shared/caller scope before confirming a deletion. Logical usage counts stored JSON; physical database size also includes database overhead and is not a customer’s billable JSON size.
Manage memory in the Function dashboard
Open Functions → your Function → Memory. The tab is available even before any data is stored and shows an empty state until your code writes memory. It is also available in the site’s Function editor and the administrator’s Function editor.
The Function owner can inspect and delete both shared and caller data belonging to that Function. Caller isolation separates callers from one another; it does not conceal application data from its owner. A caller, API-key holder, MiniUp user, or ordinary site member does not gain access to the owner’s dashboard or management API. Tell your application users how you handle their stored data and return only data each caller is authorized to access.
- Choose Production for live data or Preview for test data. They remain separate.
- Review stored key count, JSON size, shared keys, and caller keys. These summaries cover the selected environment, regardless of list filters.
- Search by key name, filter shared or caller data, and sort by last update, key name, or value size. Results are paginated at 25 keys.
- Expand Caller identity to see the opaque caller ID. Choose Show this caller’s keys to narrow the list. An opaque caller ID is not a member email, wallet address, or organization name.
- Choose View JSON to fetch the full value. The dialog shows metadata and lets you copy JSON. Values are read on demand, not all downloaded with the list. JSON can contain private information; share it only when appropriate.
- Choose Delete and review the key, environment, and shared/caller identity before confirming. Only that record is removed, including when another caller has a key with the same name.
For a full environment reset, expand Data cleanup and choose Clear production memory or Clear preview memory. Confirmation names the environment. This removes all shared and caller keys in that environment, not just the search results or selected caller. It does not affect the other environment, other Functions, or other owners. Deletion cannot be undone. Running Functions can create new records again.
Dashboard management acts on stored memory directly and does not require Save & Publish. Viewing or deleting memory does not invoke the Function or use its production-call quota. The dashboard does not provide arbitrary JSON editing; use validated Function logic to update application records. Reads are live views, so concurrent Function writes may change results between pages or between opening a value and deleting it.
Function Memory · MINIUP_MEMORY · persistent storage · JSON · preview · memory limits