The Inertia.js Challenge: Real-Time Sync
The Rails ecosystem has gravitated towards Hotwire and Turbo Streams for real-time applications. This approach excels when working with HTML-over-the-wire strategies. However, developers who prefer building frontend experiences with component frameworks like Svelte, Vue, or React, and utilize Inertia.js for server-driven routing, face a different set of challenges when real-time synchronization is required.
Without Turbo Streams, achieving real-time updates in Inertia.js applications can become complex. Common workarounds include re-fetching Inertia page props on every WebSocket event, which is inefficient, or writing custom ActionCable subscribers that manually mutate complex client-side state management. These methods often lead to convoluted code and potential synchronization issues.
A cleaner solution has emerged, leveraging a local database to mediate real-time data synchronization. This is the core idea behind DexieCable.
DexieCable: A Local Database Synchronization Layer
DexieCable positions itself as a bridge between ActionCable and a local IndexedDB database. It allows developers to push real-time data updates from the server directly into a client-side database. Inertia.js applications can then react to these changes by querying the local database, effectively updating the UI without needing to re-fetch entire page props or manually manage WebSocket message parsing and state mutations.
The library works by establishing an ActionCable connection and subscribing to specific channels. When a message arrives on a channel, DexieCable intercepts it and translates the data into operations that update the IndexedDB. Crucially, it handles the logic of ensuring these updates are applied efficiently and correctly to the client's local data store.
For the Inertia.js frontend, this means the application can listen for changes in the local IndexedDB. When data relevant to the current view is updated, the frontend framework (e.g., Svelte, Vue, React) can be notified, triggering a re-render of the affected components. This pattern decouples the real-time update mechanism from the core Inertia page navigation and prop fetching, simplifying the overall application architecture.

Implementing DexieCable with Inertia.js
The implementation involves setting up ActionCable on the Rails backend and integrating DexieCable on the frontend. On the server, you would define an ActionCable channel and broadcast data changes to subscribed clients. For example, a `PostChannel` could broadcast updates whenever a new post is created or an existing one is modified.
On the frontend, DexieCable is initialized and connected to the ActionCable server. You then define which data models or tables should be synchronized with the local IndexedDB. DexieCable subscribes to the corresponding ActionCable channels and populates the IndexedDB. Your Inertia.js components can then query this local database using Dexie.js (the underlying library for IndexedDB access) to retrieve the data they need to display. When DexieCable updates the IndexedDB, these queries will automatically reflect the latest data, prompting UI updates.
Consider a scenario where a user is viewing a list of posts. If another user creates a new post, the Rails backend broadcasts this event. DexieCable receives the broadcast, updates the local IndexedDB with the new post data, and notifies the frontend. The Inertia.js component, which is querying the local database for posts, detects the change and renders the new post in the list. This happens seamlessly without a full page refresh or explicit prop re-fetching.
Advantages Over Turbo Streams for Component Frameworks
While Turbo Streams are excellent for HTML-based updates, they can become less elegant when dealing with complex client-side state managed by frameworks like Svelte or Vue. Manually orchestrating these updates can lead to tight coupling between server-side broadcasts and client-side state management logic.
DexieCable offers several advantages in this context:
- Decoupled State Management: The local database acts as a single source of truth for real-time data on the client. Frontend components query this store, reducing the need for direct manipulation of global application state based on WebSocket messages.
- Offline Support Potential: By using IndexedDB, DexieCable lays the groundwork for potential offline capabilities. Data is available locally, and strategies can be devised to handle synchronization when connectivity is restored.
- Simplified Frontend Logic: Developers can leverage familiar Dexie.js query patterns to access real-time data, rather than parsing ActionCable messages and implementing custom state update logic within their component framework.
- Performance: Updating only the necessary data in the local database and re-rendering specific components can be more performant than re-fetching entire Inertia page props, especially for large datasets or complex pages.
This approach essentially mirrors patterns seen in PWA development and offline-first applications, bringing robust real-time synchronization to server-rendered applications using Inertia.js.
The Unanswered Question: Scalability and Conflict Resolution
While DexieCable offers a compelling alternative for real-time updates in Inertia.js applications, a key area for further exploration is its scalability and advanced conflict resolution strategies. As applications grow and more users concurrently update the same data, robust mechanisms for handling write conflicts become paramount. How does DexieCable's underlying IndexedDB interaction manage concurrent writes from different users or multiple updates from the same user? While local IndexedDB is powerful, its concurrency primitives and the strategies employed by DexieCable to ensure data integrity under heavy load will be critical for enterprise-level adoption. This remains an open question for developers considering DexieCable for large-scale, highly interactive applications.
