19Docs
App management
Your backend can create and manage other Bounded apps through ctx.apps. Use it for separate customer workspaces, temporary previews, or an app that builds other apps.
Give a Function permission
Add apps: true to the Function declaration in policy.json. Keep its auth rule restricted to the people who should manage apps.
{
"constants": { "FUNCTION_OWNER": "replace-with-your-bounded-user-id" },
"functions": {
"createWorkspace": {
"entry": "functions/createWorkspace.ts",
"auth": "@user.id == @const.FUNCTION_OWNER",
"apps": true,
"timeout": 30
}
}
}Replace the owner constant with the ID from bounded whoami --json. The platform reads this permission from the deployed policy. A caller cannot grant it through Function arguments.
Create a child app
A managed child is an app under the calling app's control. Choose its protocol and a spending ceiling when you create it.
export default async function (args, ctx) {
if (typeof args.workspaceId !== "string" || !args.workspaceId.trim()) {
throw new Error("workspaceId is required");
}
const result = await ctx.apps.create({
name: "Customer workspace",
protocol: "realtime_offchain",
ownership: "managed-child",
spendCeilingMicroUsd: 1_000_000,
idempotencyKey: "workspace:" + args.workspaceId,
});
if (!result.ok) return result;
return { appId: result.targetAppId };
}The example sets a ceiling of 1,000,000 micro-USD, which equals $1. A ceiling limits spending. It does not add credit.
Use one idempotencyKey for each intended creation. Reuse that key when you retry the same request. Check ok before you use targetAppId.
Creation gives you an app identity. Install a release or use ctx.build to add the app's policy, code, and frontend.
What ctx.apps can do
| Task | Methods |
|---|---|
| Find controlled apps and inspect their state | list, inspect |
| Read or write target app data | get, set, setMany |
| Call a target app Function | invoke |
| Set a spending ceiling or pass allowed secrets | setSpendCeiling, setSecrets |
| Copy or install a release | cloneRelease, installRelease |
| Manage a preview or its address | extendPreview, claimSlug, retire |
| Authorize and attach a user-owned app | authorizeUserApp, attachUserApp, authorizeControl |
| Delete an eligible controlled app | delete |
Writes through set and setMany still pass the target app's rules and invariants.setMany accepts up to 100 documents in one atomic write.
A user-owned app needs explicit user authorization before another app can attach or control it. Knowing an app ID does not grant access.
App management and app builds
ctx.apps manages app identities, releases, permissions, and lifecycle.ctx.build starts and inspects code builds. A Function needs a separate build declaration for those operations.
Cross-app builds also need the apps permission and control of the target. See Functions for the other backend services.
Handle failures and retries
App operations can return ok: false with a reason. Keep the result and operation ID when a request needs reconciliation.
If invoke reports reconciling, retry the same operation with the same key. Do not create a new key to repeat a potentially completed action.