Skip to main content

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:
1

User A Edits File

Types code in the editor, triggering auto-save after 1.5s
2

Mutation Executes

Convex mutation updates the file in the database
3

Push to Subscribers

Convex broadcasts the change to all subscribed clients
4

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:
  1. File is added to Convex database
  2. Query re-runs for all subscribers
  3. 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

  1. Immediate UI update - Show change instantly in local UI
  2. Send mutation - Update database in background
  3. 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:
1

User Sends Message

Message created with status “processing”
2

AI Processes

Background job generates response
3

Streaming Updates

Message content updates as AI generates response
4

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.

Performance Optimization

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
});

Database Pagination

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:
EventSync TimeVisible To
File Edit~100msAll project collaborators
File Create~50msAll project collaborators
File Delete~50msAll project collaborators
Folder Create~50msAll project collaborators
Project Rename~50msAll project collaborators
AI MessageStreamingCurrent 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

Build docs developers (and LLMs) love