Platform Services
Maravilla bundles a complete set of built-in services — identity, data, real-time, async logic, media, and notifications — all reachable through one entry point and identical between development and production.
Every Maravilla project gets its own isolated set of all of these — a private database, a private KV store, a private object store, its own auth setup, its own push keypair, its own channels and rooms. Nothing is shared across projects. There’s nothing to provision; you just call the API and the project’s services are there.
Accessing Platform Services
All services hang off the getPlatform() helper from @maravilla-labs/platform:
import { getPlatform } from '@maravilla-labs/platform';
const platform = getPlatform();
await platform.auth.login({ email, password }); // Authentication
await platform.KV.sessions.put('user:abc', token); // KV Store
await platform.DB.find('users', { active: true }); // Database
await platform.STORAGE.put('uploads/photo.jpg', data); // Storage
await platform.realtime.publish('chat:lobby', { text }); // Realtime Channels
await platform.media.createRoom('standup'); // Media Rooms
await platform.push.send({ topic: 'waitlist' }, { ... }); // Push Notifications
Services
Identity & Access
Authentication
Email/password sign-up and sign-in, OAuth providers (Google, GitHub, Okta, generic OIDC), session management, and refresh tokens. No tables to create, no JWT plumbing to write.
const session = await platform.auth.login({
email: 'jane@example.com',
password: 'securePassword123',
});
// session.access_token — short-lived JWT
// session.refresh_token — single-use refresh token
Authorization
Per-resource policies that decide who can read, write, or act on your data. Attach a rule to a resource and Maravilla evaluates it on every KV/DB/channel/room access — no if (user.id === doc.owner) scattered through your handlers.
// On the "documents" resource, set a policy in the admin UI:
// auth.user_id == node.owner || auth.is_admin
// That rule now runs on every kv.get / kv.put / db.find on that resource.
Data
KV Store
A namespaced key-value store for fast reads and writes. Ideal for session data, feature flags, caching, and any data that maps naturally to key-value pairs. Supports optional TTL-based expiration and prefix-based listing with cursor pagination.
await platform.KV.sessions.put('user:abc', JSON.stringify({ role: 'admin' }));
const session = JSON.parse(await platform.KV.sessions.get('user:abc'));
Database
A document database with a MongoDB-style query API. Comparison, logical, and element operators for filtering; sort, limit, and skip for pagination; secondary indexes; TTL; and native vector search — write queries once, the platform handles everything.
await platform.DB.insertOne('products', {
name: 'Widget',
price: 29.99,
inStock: true,
});
const affordable = await platform.DB.find('products', {
price: { $lte: 50 },
inStock: true,
}, { sort: { price: 1 }, limit: 20 });
Vector Search
Semantic similarity built into the database. Store embeddings alongside your documents, declare a vector index, and query by similarity — optionally combined with regular metadata filters in a single call. Bring your own embeddings from any provider.
await platform.DB.createVectorIndex('products', {
field: 'embedding',
dimensions: 1536,
metric: 'cosine',
});
const similar = await platform.DB.find('products',
{ inStock: true },
{ vector: { field: 'embedding', value: queryEmbedding, k: 10 } },
);
Storage
Object storage for files of any size. Direct server uploads, presigned URLs for browser-to-storage uploads, download URL generation, and file metadata.
await platform.STORAGE.put('reports/q1.pdf', pdfBuffer, {
contentType: 'application/pdf',
metadata: { generatedBy: 'reporting-service' },
});
const { url } = await platform.STORAGE.generateDownloadUrl('reports/q1.pdf', 3600);
Async & Logic
Event Handlers
Drop a file into your events/ folder and Maravilla wires it up on deploy. React to user sign-ups, database changes, queue messages, or cron schedules — no subscribe/unsubscribe calls, no background worker to keep alive.
// events/hello.ts
import { onAuth, onDbChange } from '@maravilla-labs/platform/events';
export const sendWelcome = onAuth({ op: 'registered' }, async (event) => {
console.log(`Welcome ${event.data?.email}!`);
});
export const auditUsers = onDbChange({ collection: 'users' }, async (event) => {
console.log(`[${event.op}] user ${event.id}`);
});
Workflows
Multi-step business logic written as a plain async function — and made durable for you. A workflow can sleep for a week, wait for a webhook, retry a flaky API call, and resume exactly where it left off after a crash or restart.
import { defineWorkflow } from '@maravilla-labs/platform/workflows';
export const onboarding = defineWorkflow(
{ id: 'onboarding', options: { retries: 5, timeoutSecs: 86400 } },
async (input, step, ctx) => {
const user = await step.run('fetch-user', () =>
ctx.database.findOne('users', { _id: input.userId }),
);
await step.sleep('cool-off', '1 day');
await step.run('send-tips', () => sendTips(user));
},
);
Real-time
Real-Time Events (REN)
A Server-Sent Events stream of resource mutations — KV writes, DB inserts, storage uploads — pushed to connected browsers. Build live dashboards or collaborative UIs without polling. In multi-node deployments, events fan out across all nodes automatically.
import { RenClient } from '@maravilla-labs/platform/ren';
const ren = new RenClient({ subscriptions: ['kv', 'db'] });
ren.on((event) => {
console.log(event.t, event.k); // e.g. "kv.put", "todo:abc123"
});
Realtime Channels
Bidirectional pub/sub messaging plus presence tracking over WebSocket. Your server publishes through platform.realtime; browsers connect to /_rt/ws and subscribe.
await platform.realtime.publish('chat:lobby', {
text: 'Hello everyone!',
}, { userId: 'alice' });
const members = await platform.realtime.presence.members('chat:lobby');
Media Rooms
Add video and audio calling to your app. Your server creates rooms and mints participant tokens; clients connect directly to the media server with any WebRTC-compatible library.
const room = await platform.media.createRoom('standup', { maxParticipants: 10 });
const { token, url } = await platform.media.generateToken('standup', {
identity: 'alice',
name: 'Alice',
});
Media & Outbound
Media Transforms
Turn anything users upload into the shape you actually want to serve. Transcode a wobbly phone-recorded webm into clean mp4, pull a poster frame, resize photos, OCR a scanned PDF, convert Word docs, or fill a .docx template. Your code asks for the transform; the platform queues, runs, and stores the result.
const job = await platform.media.transforms.thumbnail('uploads/videos/clip.webm', {
at: '1s',
width: 640,
format: 'jpg',
});
// Serve the derived file at /api/v/{job.outputKey}
Push Notifications
Real Web Push notifications — the kind that appear even with the tab closed. Send immediately or schedule for later (an hour before an event, every Monday at 9am). VAPID keys, service worker, encryption, subscription storage, and scheduling all handled.
// Browser
import { registerPush } from '@maravilla-labs/platform/push';
await registerPush({ topics: ['waitlist'] });
// Server
await platform.push.send(
{ topic: 'waitlist' },
{ title: 'Doors open!', body: 'Your spot is ready.', url: '/event/123' },
);
Development vs Production
In development, the CLI runs the full platform locally. In production, Maravilla Cloud handles everything. Your code works identically in both environments.
await platform.DB.find('users', { age: { $gte: 18 }, active: true });
You never need to worry about the underlying infrastructure — write your code once and it runs everywhere.
Multi-Layer Caching
In production, both the KV Store and Database benefit from an integrated multi-layer cache:
- L1 (in-process) — fast hot lookups within a single runtime instance.
- L2 (distributed) — shared across all processes and nodes for cluster-wide coherence.
Caching uses a versioned invalidation strategy: writes bump a version counter, making all previously cached entries instantly unreachable. This guarantees no stale data is ever served after a write. If the distributed cache is unavailable, the system operates without it transparently. Other services (Storage, Channels, REN, Media) have their own per-service performance characteristics documented on their respective pages.
Next Steps
Identity & Access
- Authentication — email/password, OAuth, sessions
- Authorization — per-resource policies
Data
- KV Store — key-value operations
- Database — document query, mutation, indexing
- Vector Search — semantic similarity with embeddings
- Storage — file uploads, downloads, presigned URLs
Async & Logic
- Event Handlers — react to platform events
- Workflows — durable, multi-step business logic
Real-time
- Real-Time Events (REN) — SSE stream of resource mutations
- Realtime Channels — pub/sub + presence over WebSocket
- Media Rooms — WebRTC video/audio rooms
Media & Outbound
- Media Transforms — transcode, thumbnails, OCR, docx
- Push Notifications — Web Push, scheduled or immediate