Why Migrate to Cosmictron?
MongoDB Realm's deprecation left thousands of applications without a clear migration path. While Firebase and Supabase are common alternatives, they don't offer the same architecture as Realm. Cosmictron does—and improves upon it.
Migration Timeline
Most teams complete their migration in 1-2 days for simple apps, or 1-2 weeks for complex production systems with extensive Realm Functions and Triggers.
| Feature | MongoDB Realm | Cosmictron |
|---|---|---|
| Offline Sync | Device Sync (now deprecated) | Planned (CRDT-based) |
| Serverless Functions | Realm Functions | Reducers (WASM/V8) |
| Real-time Sync | Live Queries | DBSP Incremental Subscriptions |
| Data Storage | MongoDB Atlas | Embedded (in-memory with WAL) |
| Triggers | Database Triggers | Lifecycle Hooks |
| Hosting | Managed (Atlas) | Self-hosted or Managed |
Concept Mapping
Device Sync → Real-time Subscriptions
Realm's Device Sync kept local MongoDB collections in sync with the cloud. In Cosmictron, clients subscribe to SQL queries and receive incremental deltas automatically.
// Realm (old) const collection = realm.objects('Task'); const listener = collection.addListener(() => { console.log('Tasks changed'); }); // Cosmictron (new) const subscription = await client.subscribe( 'SELECT * FROM tasks WHERE user_id = ?', { user_id: currentUser.id } ); subscription.on('update', ({ inserts, deletes, updates }) => { inserts.forEach(task => console.log('New task:', task)); });
Realm Functions → Reducers
Realm Functions were serverless JavaScript functions. Cosmictron uses reducers—ACID-transactional functions written in Rust or TypeScript that run inside the database.
// Realm Function (old) exports = async function createTask(title) { const collection = context.services.get("mongodb-atlas") .db("app").collection("tasks"); return await collection.insertOne({ title, createdAt: new Date() }); }; // Cosmictron Reducer (new) #[reducer] pub fn create_task(title: String) { let task = Task { id: 0, // auto-assigned title, created_at: ctx.timestamp(), user_id: ctx.sender(), }; ctx.db.tasks().insert(&task); }
Triggers → Lifecycle Hooks
Realm Triggers responded to database changes. Cosmictron provides lifecycle hooks that run during module initialization, client connection, and disconnection.
// Realm Trigger (old) exports = async function onUserChange(changeEvent) { const user = changeEvent.fullDocument; await context.services.get("mongodb-atlas") .db("app").collection("logs") .insertOne({ event: 'user_updated', user }); }; // Cosmictron Lifecycle (new) #[reducer(lifecycle = "client_connected")] pub fn on_client_connected() { ctx.db.user_presence().insert(&Presence { user_id: ctx.sender(), status: "online", last_seen: ctx.timestamp(), }); }
Migration Steps
1. Export Your Realm Data
Before migrating, export your data from MongoDB Atlas:
- Go to your Atlas cluster
- Use
mongodumpto export collections - Convert BSON to JSON for easier processing
2. Define Your Schema
Convert your Realm object models to Cosmictron table definitions:
// Realm Schema (old) const TaskSchema = { name: 'Task', properties: { _id: 'objectId', title: 'string', completed: 'bool', user_id: 'string', createdAt: 'date', } }; // Cosmictron Table (new) #[table(name = "tasks", public)] pub struct Task { #[primary_key] #[auto_inc] pub id: u64, pub title: String, pub completed: bool, #[index] pub user_id: String, #[index] pub created_at: u64, }
3. Migrate Business Logic
Convert Realm Functions to reducers. Each Realm Function typically becomes one reducer:
- CRUD operations → Reducers with
#[reducer] - Authentication logic → RLS policies + identity checks
- Validation → Type system + reducer logic
4. Update Client Code
Replace Realm SDK calls with Cosmictron client SDK:
// Realm (old) const realm = await Realm.open({ schema: [TaskSchema] }); await realm.write(() => { realm.create('Task', { title: 'Buy milk', completed: false }); }); // Cosmictron (new) const client = new CosmictronClient('ws://localhost:3000'); await client.connect(); await client.callReducer('tasks', 'create_task', { title: 'Buy milk' });
5. Deploy and Test
- Start Cosmictron server:
cosmictron-server - Deploy your module:
cosmictron deploy ./module.wasm - Run integration tests
- Migrate production data
- Update DNS and go live
Common Migration Challenges
Offline-First Apps
Realm's offline sync was a key feature. Cosmictron doesn't have full offline support yet (planned for v2), but you can implement optimistic updates:
- Queue mutations locally when disconnected
- Apply optimistic updates to UI immediately
- Sync when connection restored
Complex Aggregations
Realm allowed complex aggregation pipelines. In Cosmictron, use SQL subscriptions with DBSP incremental maintenance:
-- Real-time aggregation with automatic updates SELECT status, COUNT(*) as count, MAX(created_at) as last_updated FROM tasks WHERE user_id = ? GROUP BY status
User Authentication
Realm provided built-in auth. In Cosmictron, bring your own auth (JWT recommended) and use RLS for authorization:
#[table(name = "tasks", public)] #[rls(read = "user_id = ctx.sender()")] #[rls(write = "user_id = ctx.sender()")] pub struct Task { #[primary_key] pub id: u64, #[index] pub user_id: Identity, pub title: String, }
Need Help?
Migration can be complex. We're here to help:
- GitHub Issues: github.com/cosmictron/cosmictron/issues
- Documentation: cosmictron.io/docs
- Community: Join our Discord (coming soon)