Engine Modes
Programmatic vs Interactive mode.
superapp supports two engine modes that control how permissions and connections are managed. Choose the mode that matches your team's workflow.
Side-by-Side Comparison
| Feature | programmatic | interactive |
|---|---|---|
| Permissions defined in | Code (createEngine config) | Admin UI (stored in metadata DB) |
| Connections defined in | Code (createEngine config) | Admin UI (stored in metadata DB) |
| Roles defined in | Code (createEngine config) | Admin UI (stored in metadata DB) |
| Version control | Git-tracked, PR-reviewed | Database-stored, audit-logged |
| Admin UI | Read-only dashboard (view-only access to config defined in code) | Full editing capabilities (create, edit, and delete permissions, connections, and roles) |
| Deployment | Config changes require redeploy | Changes take effect immediately |
| Default | Yes | No |
| Best for | Engineering teams, CI/CD pipelines | Non-technical admins, rapid iteration |
Programmatic Mode
In programmatic mode, permissions, connections, and roles are defined entirely in your createEngine configuration. The source code is the single source of truth.
const engine = createEngine({
mode: 'programmatic', // this is the default
connections: {
main: process.env.PG_URL!,
},
permissions: {
view_own_orders: {
name: 'View own orders',
table: 'main.orders',
roles: ['viewer', 'editor'],
select: {
columns: ['id', 'amount', 'status', 'created_at'],
where: { customer_id: { $eq: '$user.customer_id' } },
},
},
edit_own_orders: {
name: 'Edit own orders',
table: 'main.orders',
roles: ['editor'],
update: {
columns: ['amount', 'status', 'notes'],
where: { customer_id: { $eq: '$user.customer_id' } },
validate: { status: { $in: ['draft', 'active'] } },
overwrite: { updated_by: '$user.id' },
},
},
},
})How It Works
- You define permissions and roles in TypeScript.
- Changes go through your normal code review process (PR, CI, tests).
- The admin UI (if accessed) shows permissions in read-only mode for visibility.
- The engine reads the config once at startup. Changes require a restart or redeploy.
When to Use Programmatic Mode
- Your team uses git-based workflows and wants permissions in version control.
- You want PR reviews on permission changes.
- You need reproducible deployments where the same code always produces the same behavior.
- You have a CI/CD pipeline that deploys config changes.
- Security is paramount and you want to audit permission changes in git history.
Interactive Mode
In interactive mode, the admin UI becomes the primary interface for managing permissions, connections, and roles. Changes are stored in the metadata database and take effect immediately — no code changes or redeployments needed.
const engine = createEngine({
mode: 'interactive',
superapp_db: process.env.TURSO_URL ?? './superapp.db',
masterKey: process.env.SUPERAPP_MASTER_KEY!,
auth: betterAuthProvider({ /* ... */ }),
// No permissions or roles here — they live in the admin UI
})How It Works
- Start the engine with
mode: 'interactive'and amasterKey. - Access the admin UI (served by the engine on the
/adminroute). - Add connections, define permissions, and assign roles visually.
- Changes are persisted to the metadata database and applied immediately.
- All admin actions are audit-logged.
Interactive Mode Capabilities
In interactive mode, the admin UI provides:
- Connection management -- Add, edit, and test database connections.
- Permission editor -- Visual builder for where clauses, columns, validate, and default/overwrite rules.
- Role management -- Assign roles inline on permissions and actions.
- User management -- View users, assign roles, manage sessions.
- Audit log viewer -- Browse query and admin action logs.
- Schema browser -- Explore attached database tables and columns.
When to Use Interactive Mode
- Non-technical team members need to manage access rules.
- You want to iterate on permissions without redeploying.
- You are building a multi-tenant platform where customers configure their own access rules.
- Rapid prototyping where you are still figuring out the permission model.
Switching Between Modes
You can switch from programmatic to interactive mode at any time. When switching to interactive mode, any permissions defined in code are imported into the metadata database as a starting point.
Switching from interactive back to programmatic requires exporting your current permissions from the admin UI and adding them to your createEngine config.
// Start in programmatic mode during development
const engine = createEngine({
mode: 'programmatic',
permissions: { /* ... */ },
})
// Later, switch to interactive mode for production
const engine = createEngine({
mode: 'interactive',
masterKey: process.env.SUPERAPP_MASTER_KEY!,
// permissions from code are imported into the metadata DB on first run
})Hybrid Approach
Some teams use programmatic mode in production with interactive mode in staging. This lets you:
- Prototype permission changes in the staging admin UI.
- Export the tested configuration.
- Add it to your codebase and deploy through CI/CD.
const engine = createEngine({
mode: process.env.NODE_ENV === 'production' ? 'programmatic' : 'interactive',
permissions: {
// These are always available as a baseline
view_own_orders: { /* ... */ },
},
masterKey: process.env.SUPERAPP_MASTER_KEY!,
})