Skip to main content

Overview

Polaris IDE provides a powerful file explorer with real-time synchronization, drag-and-drop support, and efficient file operations backed by Convex database.

Tree View

Hierarchical file and folder navigation

Real-Time Sync

Changes appear instantly across all sessions

Cloud Storage

All files stored securely in Convex database

File Explorer Interface

Project Navigation

The file explorer shows your project structure in a collapsible tree:
📁 MY PROJECT
  📄 package.json
  📁 src
    📁 components
      📄 Button.tsx
      📄 Card.tsx
    📁 lib
      📄 utils.ts
    📄 index.ts
  📄 README.md
Click the chevron (▶) next to the project name to expand/collapse the entire tree.

Quick Actions

Hover over the project name to reveal quick action buttons:

New File

Create a new file at the root level

New Folder

Create a new folder at the root level

Collapse All

Collapse all expanded folders

Creating Files & Folders

Creating a New File

1

Open Create Input

Click the File+ icon or right-click in the explorer
2

Enter Filename

Type the filename with extension (e.g., app.tsx)
3

Confirm

Press Enter to create or Esc to cancel
// From file-explorer/index.tsx
const handleCreate = (name: string) => {
  if (creating === "file") {
    createFile({
      projectId,
      name,
      content: "",
      parentId: undefined,  // Root level
    });
  }
};

Creating a New Folder

The process is identical to creating files:
To create files/folders inside a folder:
  1. Hover over the parent folder
  2. Click the + icon that appears
  3. Choose File or Folder from the context menu
  4. Enter the name and press Enter
createFolder({
  projectId,
  name: "components",
  parentId: parentFolderId,  // Nested folder
});

File Operations

Renaming Files

1

Enter Rename Mode

Right-click file → Rename or press F2
2

Edit Name

Type the new name (keep the file extension)
3

Save

Press Enter to save or Esc to cancel
// From use-files.ts
const renameFile = useMutation(api.files.renameFile);

renameFile({ 
  id: fileId, 
  name: "new-name.tsx" 
});

Deleting Files

Deleting a folder will recursively delete all files and subfolders inside it. This action cannot be undone.
const deleteFile = useMutation(api.files.deleteFile);

deleteFile({ id: fileId });

Moving Files

Drag-and-drop file moving is planned for a future release. Currently, you can copy content and recreate files in new locations.

File Explorer Features

Lazy Loading

Folders load their contents only when expanded:
const useFolderContents = ({
  projectId,
  parentId,
  enabled = true,  // Only fetch when folder is open
}) => {
  return useQuery(
    api.files.getFolderContents,
    enabled ? { projectId, parentId } : "skip",
  );
};

Performance Optimization

Only visible folder contents are loaded from the database, keeping the UI fast even with hundreds of files.

File Icons

Polaris uses VSCode-style icons to identify file types:
IconFile TypeExtensions
📄Text file.txt, .md
⚛️React.jsx, .tsx
🟦TypeScript.ts, .tsx
🟨JavaScript.js, .jsx
🎨Styles.css, .scss
📦Packagepackage.json
📋Config.json, .yaml

Collapsible Tree

Every folder can be expanded or collapsed:
// From file-explorer/tree.tsx
const [isOpen, setIsOpen] = useState(true);

<div onClick={() => setIsOpen(!isOpen)}>
  <ChevronRightIcon className={isOpen && "rotate-90"} />
  {item.name}
</div>
Use the Collapse All button to quickly close all expanded folders and see your project structure at a glance.

Database Schema

Files are stored in Convex with the following structure:
// From convex/schema.ts
files: defineTable({
  projectId: v.id("projects"),
  parentId: v.optional(v.id("files")),  // For nested files
  name: v.string(),
  type: v.union(v.literal("file"), v.literal("folder")),
  content: v.optional(v.string()),      // Text files only
  storageId: v.optional(v.id("_storage")), // Binary files
  updatedAt: v.number(),
})
  .index("by_project", ["projectId"])
  .index("by_parent", ["parentId"])
  .index("by_project_parent", ["projectId", "parentId"]);
Key Points:
  • parentId is undefined for root-level files
  • Text files use content field
  • Binary files (images, etc.) use storageId
  • Indexes optimize queries for folder contents

File Types

Text Files

Stored directly in the database as strings:
{
  name: "app.tsx",
  type: "file",
  content: "import React from 'react';\n\n...",
  storageId: undefined,
}

Binary Files

Stored in Convex file storage with a reference:
{
  name: "logo.png",
  type: "file",
  content: undefined,
  storageId: "kg24jv8s9q2...",  // Reference to _storage
}
Binary files display a special preview with download options instead of opening in the editor.

Real-Time Updates

All file operations sync instantly using Convex:
1

User Creates File

Local optimistic update shows file immediately
2

Mutation Sent

Convex mutation processes on the server
3

Broadcast Update

All connected clients receive the new file
4

UI Updates

File appears in all open sessions
// Convex automatically syncs changes
const rootFiles = useFolderContents({
  projectId,
  enabled: isOpen,
});

// When another user creates a file, rootFiles updates automatically

Auto-Save

File content is automatically saved as you type:

Debounced Saves

  • 1.5 seconds after you stop typing
  • Prevents excessive database writes
  • Ensures you never lose work
const DEBOUNCE_MS = 1500;

onChange={(content: string) => {
  if (timeoutRef.current) {
    clearTimeout(timeoutRef.current);
  }

  timeoutRef.current = setTimeout(() => {
    updateFile({ id: activeFile._id, content });
  }, DEBOUNCE_MS);
}}
The editor saves automatically - you don’t need to manually save files!

File Path Resolution

Polaris maintains full file paths for nested files:
// Build path by traversing parent chain
const buildPath = (fileId: string): string => {
  const pathSegments: string[] = [];
  let currentId = fileId;

  while (currentId) {
    const file = fileMap.get(currentId);
    if (!file) break;
    pathSegments.unshift(file.name);
    currentId = file.parentId;
  }

  return pathSegments.join("/");
};

// Example result: "src/components/Button.tsx"

Loading States

The file explorer shows loading indicators:
{rootFiles === undefined && <LoadingRow level={0} />}
{rootFiles?.map((item) => (
  <Tree key={item._id} item={item} />
))}
// From file-explorer/loading-row.tsx
export const LoadingRow = ({ level }: { level: number }) => (
  <div 
    className="flex items-center gap-2 px-2 py-1"
    style={{ paddingLeft: `${level * 16}px` }}
  >
    <Spinner className="size-3" />
    <span className="text-muted-foreground">Loading...</span>
  </div>
);

Context Menus

Right-click files and folders for quick actions:
  • New File - Create file in current folder
  • New Folder - Create subfolder
  • Rename - Change file/folder name
  • Delete - Remove file/folder
  • Copy Path - Copy full file path
Context menu implementation uses native browser context menu API for optimal performance.

Best Practices

Organize by Feature

Group related files in feature-based folders (e.g., components/, hooks/, lib/)

Use Clear Names

Name files descriptively (e.g., UserProfile.tsx not up.tsx)

Keep It Shallow

Avoid deeply nested folder structures (3-4 levels max)

Clean Up Regularly

Delete unused files to keep projects organized

Next Steps

Code Editor

Learn how to edit files in the code editor

WebContainer Execution

Run your code in the browser-based terminal

Build docs developers (and LLMs) love