createEngine Options
Complete configuration reference.
createEngine accepts a single configuration object and returns an engine instance. This page documents every available option.
import { createEngine } from '@superapp/backend'
const engine = createEngine({
connections: {
main: 'postgres://localhost:5432/mydb',
},
})Top-Level Options
Prop
Type
connections
Each connection maps a name to a database URL or config object. The engine infers the database type from the URL protocol — no explicit type field needed.
connections: {
main: 'postgres://localhost:5432/mydb', // postgres
warehouse: 'mysql://localhost:3306/warehouse', // mysql
legacy: './legacy.db', // sqlite
imports: { directory: './data/imports/' }, // csv
}Type Inference
| URL / Config | Inferred Type |
|---|---|
postgres://... or postgresql://... | PostgreSQL |
mysql://... | MySQL |
File path (.db, .sqlite) or file:... | SQLite |
libsql://... or Turso URL | SQLite (Turso) |
{ directory: string } | CSV |
Examples
// Single Postgres
connections: {
main: process.env.PG_URL!,
}
// Multiple databases
connections: {
main: process.env.PG_URL!,
warehouse: process.env.MYSQL_URL!,
legacy: './legacy.db',
imports: { directory: './data/imports/' },
}permissions
Permission definitions using Drizzle-like syntax. Each permission targets a table, declares which roles have access, and configures operations (select, insert, update, delete) individually.
permissions: {
view_own_orders: {
table: 'main.orders',
roles: ['viewer', 'editor', 'admin'],
select: {
columns: ['id', 'amount', 'status', 'created_at'],
where: { customer_id: { $eq: '$user.customer_id' } },
},
},
}See Permission Object for the complete shape reference.
actions
Typed server-side functions with inline roles. Each action defines its allowed roles directly.
actions: {
incrementStock: {
roles: ['warehouse_manager', 'admin'],
input: z.object({ productId: z.string(), amount: z.number().positive() }),
output: z.object({ id: z.string(), stock: z.number() }),
run: async ({ user, db }, { productId, amount }) => {
const [updated] = await db
.update(products)
.set({ stock: sql`stock + ${amount}` })
.where(eq(products.id, productId))
.returning({ id: products.id, stock: products.stock })
return updated
},
},
},See Actions for full documentation.
limits
Query complexity and rate limit constraints to prevent abuse and protect your databases.
Prop
Type
Prop
Type
Prop
Type
limits: {
maxRows: 5000, // max rows a query can return
maxRelationDepth: 2, // orders → items = depth 2
maxFilterNesting: 4, // nested $and/$or/$not levels
maxFilterConditions: 30, // total conditions per query
maxRequestBodySize: '2mb', // max JSON body size
queryTimeout: 15_000, // kill slow queries (ms)
rateLimitPerUser: 100, // req/min per user
rateLimitPerIP: 300, // req/min per IP
}audit
Configure audit logging for queries, permission denials, and admin actions.
Prop
Type
Prop
Type
audit: {
enabled: true, // turn logging on/off
logQuery: true, // log SQL statements
logParams: false, // log query params (may contain sensitive data)
logDuration: true, // log query time (ms)
logUser: true, // log who ran each query
logDenied: true, // log permission denials
logAdminActions: true, // log admin UI changes
retention: '90d', // auto-delete after 90 days
piiRedaction: true, // strip emails & phone numbers
}jwt
JWT verification settings. These configure how the auth provider validates incoming tokens.
Prop
Type
jwt: {
algorithms: ['RS256', 'ES256'], // allowed signing algorithms
issuer: 'https://auth.myapp.com', // reject tokens from other issuers
audience: 'https://api.myapp.com', // reject tokens for other audiences
clockSkewSeconds: 10, // clock drift tolerance (seconds)
}security
Network security, CORS, and access control settings.
Prop
Type
Prop
Type
security: {
cors: {
origin: ['https://myapp.com', 'https://admin.myapp.com'], // allowed origins
credentials: true, // allow cookies
maxAge: 86400, // preflight cache (seconds)
},
csp: "default-src 'self'; script-src 'self'", // CSP header for admin UI
adminIpAllowlist: ['10.0.0.0/8', '192.168.1.0/24'], // restrict /admin access
}schemaEndpoint
Enable the GET /schema endpoint for schema introspection.
Prop
Type
schemaEndpoint: true // shorthand — enable with defaults
schemaEndpoint: {
enabled: true, // expose GET /schema
token: process.env.SCHEMA_API_TOKEN, // require token for access
}pgWire
Configure the PostgreSQL wire protocol server. When configured, calling engine.startPgWire() starts a TCP server that speaks the PostgreSQL wire protocol.
Prop
Type
Prop
Type
Prop
Type
// Shorthand — enable with defaults (port 5433, trust auth)
pgWire: true
// Full configuration
pgWire: {
port: 5433,
auth: { strategy: ['jwt', 'apiKey'] },
tls: {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt'),
},
serverVersion: '16.3 (superapp)',
}See PostgreSQL Wire Protocol for usage guide.
Full Example
import { createEngine } from '@superapp/backend'
import { betterAuthProvider } from '@superapp/backend/auth/better-auth'
const engine = createEngine({
mode: 'programmatic', // config in code (or 'interactive')
superapp_db: process.env.TURSO_URL ?? './superapp.db', // internal tables storage
masterKey: process.env.SUPERAPP_MASTER_KEY!, // admin API key (use env var)
connections: {
main: process.env.PG_URL!, // namespace: main.*
warehouse: process.env.MYSQL_URL!, // namespace: warehouse.*
},
auth: betterAuthProvider({ // omit for open mode (no auth)
secret: process.env.AUTH_SECRET!,
userTable: {
table: 'main.users',
matchOn: { column: 'id', jwtField: 'id' },
columns: ['id', 'email', 'name'],
},
}),
jwt: {
algorithms: ['RS256'], // allowed signing algorithms
issuer: 'https://auth.myapp.com', // reject other issuers
audience: 'https://api.myapp.com', // reject other audiences
clockSkewSeconds: 5, // clock drift tolerance
},
limits: {
maxRows: 10_000, // max rows a query can return
maxRelationDepth: 3, // orders → items → product = depth 3
maxFilterNesting: 5, // nested $and/$or/$not levels
maxFilterConditions: 50, // total conditions per query
maxRequestBodySize: '1mb', // max JSON body size
queryTimeout: 30_000, // kill slow queries (ms)
rateLimitPerUser: 200, // req/min per user
rateLimitPerIP: 500, // req/min per IP
},
audit: {
enabled: true, // turn logging on/off
logQuery: true, // log SQL statements
logParams: false, // log query params (may contain sensitive data)
logDuration: true, // log query time (ms)
logUser: true, // log who ran each query
logDenied: true, // log permission denials
logAdminActions: true, // log admin UI changes
retention: '90d', // auto-delete after 90 days
piiRedaction: true, // strip emails & phone numbers
},
security: {
cors: {
origin: ['https://myapp.com'], // allowed origins (never '*' in prod)
credentials: true, // allow cookies
},
adminIpAllowlist: ['10.0.0.0/8'], // restrict /admin access
},
schemaEndpoint: {
enabled: true, // expose GET /schema
token: process.env.SCHEMA_API_TOKEN, // require token for access
},
permissions: {
view_own_orders: {
table: 'main.orders',
roles: ['viewer', 'warehouse_manager'],
select: {
columns: ['id', 'amount', 'status', 'created_at'],
where: { customer_id: { $eq: '$user.customer_id' } },
},
},
},
actions: {
incrementStock: {
roles: ['warehouse_manager'],
input: z.object({ productId: z.string(), amount: z.number().positive() }),
output: z.object({ id: z.string(), stock: z.number() }),
run: async ({ user, db }, { productId, amount }) => {
const [updated] = await db
.update(products)
.set({ stock: sql`stock + ${amount}` })
.where(eq(products.id, productId))
.returning({ id: products.id, stock: products.stock })
return updated
},
},
},
pgWire: {
port: 5433, // TCP port for wire protocol
auth: { strategy: ['jwt', 'apiKey'] }, // auth strategies (try in order)
serverVersion: '16.3 (superapp)', // version string for clients
},
})
engine.startPgWire()