Overview
Polaris IDE uses Convex as its real-time database backend, enabling instant synchronization of all project changes across multiple users and sessions.
Instant Sync Changes appear in real-time across all connected clients
Optimistic UI Local updates show immediately, then sync to server
Conflict-Free Automatic conflict resolution with last-write-wins
How It Works
Convex provides a reactive database that automatically pushes updates to all subscribed clients:
import { useQuery , useMutation } from "convex/react" ;
import { api } from "../../../convex/_generated/api" ;
// Subscribe to real-time updates
const files = useQuery ( api . files . getFiles , { projectId });
// Files automatically update when ANY user makes changes
You don’t need to write any sync logic - Convex handles all real-time updates automatically!
Real-Time Features
File Synchronization
When one user edits a file, all other users see the changes:
User A Edits File
Types code in the editor, triggering auto-save after 1.5s
Mutation Executes
Convex mutation updates the file in the database
Push to Subscribers
Convex broadcasts the change to all subscribed clients
User B Sees Update
File content updates automatically in User B’s editor
// From use-files.ts
export const useFile = ( fileId : Id < "files" > | null ) => {
return useQuery ( api . files . getFile , fileId ? { id: fileId } : "skip" );
};
// Automatically re-runs when file changes in database
Project Updates
Project-level changes (name, settings) sync instantly:
const project = useProject ( projectId );
// Automatically updates when project.name changes
< p >{project?.name ?? "Loading..." } </ p >
File Explorer Updates
New files and folders appear in real-time:
// From use-files.ts
export const useFolderContents = ({
projectId ,
parentId ,
enabled = true ,
}) => {
return useQuery (
api . files . getFolderContents ,
enabled ? { projectId , parentId } : "skip" ,
);
};
When User A creates a file:
File is added to Convex database
Query re-runs for all subscribers
User B’s file explorer updates automatically
Convex Architecture
Database Schema
Convex stores all data in real-time reactive tables:
Users Authentication and subscription data
Projects Project metadata and ownership
Files File content and folder structure
Conversations AI chat history and messages
// From convex/schema.ts
export default defineSchema ({
projects: defineTable ({
name: v . string (),
ownerId: v . string (),
userId: v . optional ( v . id ( "users" )),
updatedAt: v . number (),
}). index ( "by_owner" , [ "ownerId" ]) ,
files: defineTable ({
projectId: v . id ( "projects" ),
parentId: v . optional ( v . id ( "files" )),
name: v . string (),
type: v . union ( v . literal ( "file" ), v . literal ( "folder" )),
content: v . optional ( v . string ()),
updatedAt: v . number (),
})
. index ( "by_project" , [ "projectId" ])
. index ( "by_parent" , [ "parentId" ]) ,
}) ;
Queries vs Mutations
Queries subscribe to data and re-run on changes:// convex/files.ts
export const getFile = query ({
args: { id: v . id ( "files" ) },
handler : async ( ctx , { id }) => {
const identity = await verifyAuth ( ctx );
const file = await ctx . db . get ( id );
// ... ownership validation
return file ;
},
});
Mutations modify data and trigger updates:export const updateFile = mutation ({
args: {
id: v . id ( "files" ),
content: v . string ()
},
handler : async ( ctx , { id , content }) => {
const identity = await verifyAuth ( ctx );
await ctx . db . patch ( id , {
content ,
updatedAt: Date . now (),
});
},
});
Optimistic Updates
Polaris uses optimistic UI updates for instant feedback:
Optimistic Pattern
Immediate UI update - Show change instantly in local UI
Send mutation - Update database in background
Confirm or rollback - Sync confirms or reverts on error
// From use-files.ts
export const useCreateFile = () => {
return useMutation ( api . files . createFile );
// TODO: Add optimistic mutation
};
Optimistic updates are planned for file operations. Currently, operations show after server confirmation (~50-200ms).
Authentication & Security
All Convex operations verify user identity:
// From convex/auth.ts
export async function verifyAuth ( ctx : QueryCtx | MutationCtx ) {
const identity = await ctx . auth . getUserIdentity ();
if ( ! identity ) {
throw new ConvexError ( "Unauthorized" );
}
return identity ;
}
Users can only access projects they own. Attempting to access another user’s project will result in an authorization error.
Ownership Validation
Every operation checks ownership:
// From convex/projects.ts
export const getProject = query ({
handler : async ( ctx , { id }) => {
const identity = await verifyAuth ( ctx );
const project = await ctx . db . get ( id );
if ( ! project ) {
throw new ConvexError ( "Project not found" );
}
// Verify ownership
if ( project . ownerId !== identity . subject ) {
throw new ConvexError ( "Unauthorized" );
}
return project ;
},
});
Real-Time AI Conversations
AI chat messages stream in real-time:
User Sends Message
Message created with status “processing”
AI Processes
Background job generates response
Streaming Updates
Message content updates as AI generates response
Status Change
Message status changes to “completed”
// From convex/schema.ts
messages : defineTable ({
conversationId: v . id ( "conversations" ),
role: v . union ( v . literal ( "user" ), v . literal ( "assistant" )),
content: v . string (),
status: v . optional (
v . union (
v . literal ( "processing" ),
v . literal ( "completed" ),
v . literal ( "failed" )
)
),
})
Database Indexes
Convex uses indexes for optimal query performance:
files : defineTable ({
// ... fields
})
. index ( "by_project" , [ "projectId" ]) // List all files in project
. index ( "by_parent" , [ "parentId" ]) // List folder contents
. index ( "by_project_parent" , [ "projectId" , "parentId" ]) // Optimized folder query
Why indexes matter:
Fast lookups without scanning entire table
Enable efficient filtering and sorting
Critical for real-time performance with large datasets
Conflict Resolution
Convex uses last-write-wins for conflict resolution:
If two users edit the same file simultaneously, the last save wins. For collaborative editing with operational transforms, consider integrating a CRDT library.
// Update includes timestamp
await ctx . db . patch ( fileId , {
content: newContent ,
updatedAt: Date . now (), // Latest timestamp wins
});
Connection Status
Convex provides connection state management:
import { useConvexAuth } from "convex/react" ;
const { isLoading , isAuthenticated } = useConvexAuth ();
if ( isLoading ) {
return < LoadingSpinner />;
}
Convex automatically handles reconnection if the user’s internet connection drops.
Skip Unnecessary Queries
Use "skip" to prevent queries from running:
const file = useQuery (
api . files . getFile ,
fileId ? { id: fileId } : "skip" // Don't query if no file selected
);
Conditional Subscriptions
Only subscribe to data you need:
const rootFiles = useFolderContents ({
projectId ,
enabled: isOpen , // Only fetch when folder is expanded
});
For projects with hundreds of files, implement pagination using Convex’s paginate() helper for optimal performance.
Multi-Device Support
The same user can work on multiple devices:
Desktop + Web Edit on desktop app, see changes on web instantly
Multiple Tabs Open same project in multiple tabs - all stay in sync
Real-Time Events
Polaris syncs these events in real-time:
Event Sync Time Visible To File Edit ~100ms All project collaborators File Create ~50ms All project collaborators File Delete ~50ms All project collaborators Folder Create ~50ms All project collaborators Project Rename ~50ms All project collaborators AI Message Streaming Current conversation
Sync times depend on network latency. Convex typically delivers updates in 50-200ms on broadband connections.
Best Practices
Trust the Sync Don’t implement manual refresh buttons - Convex handles updates automatically
Use Optimistic UI Show changes immediately for better UX, let Convex handle sync
Validate Ownership Always check user permissions in mutations and queries
Index Wisely Add database indexes for frequently queried fields
Limitations
Collaborative editing (like Google Docs) is not yet supported
File locking is not implemented - concurrent edits use last-write-wins
Presence indicators (who’s viewing what) are not currently shown
Next Steps
File Management Learn how to create and organize files
WebContainer Execution Run your code with in-browser execution