A production-ready, real-time collaborative text editor built with Next.js, TipTap, and Yjs. Features include multi-cursor presence, offline support, autosave, and role-based document sharing with a modern, beautiful UI.
- ✅ Real-time Collaboration: Multiple users can edit documents simultaneously with conflict-free merges using Yjs CRDT
- ✅ Document Sharing: Share via link or invite by email with granular permissions (Owner/Editor/Viewer)
- ✅ Multi-cursor Presence: See active collaborators and their cursor positions in real-time
- ✅ Offline Support: Continue editing when offline with IndexedDB persistence - syncs automatically when reconnected
- ✅ Autosave: Changes are automatically saved to database every 2 seconds
- ✅ Role-based Permissions: Full control over who can view, edit, or manage your documents
- ✅ Rich Text Editing: Full formatting toolbar (bold, italic, headings, lists, quotes, code blocks)
- ✅ Beautiful Modern UI: Gradient designs, smooth animations, and intuitive interface
- ✅ Secure Authentication: User authentication with NextAuth.js and bcrypt password hashing
- Frontend: Next.js 15 (App Router), React 19, TypeScript
- Editor: TipTap v2 (ProseMirror wrapper) with collaboration extensions
- Real-time: Yjs CRDT + y-websocket v2 protocol
- Styling: Tailwind CSS v3 with custom design system
- Database: SQLite with Prisma ORM (production: PostgreSQL)
- Authentication: NextAuth.js with JWT sessions
- WebSocket Server: Custom Node.js + ws + y-websocket
- Node.js 18+ installed
- npm or yarn package manager
- Clone the repository:
cd "Collaborative Text Editor"- Install dependencies:
npm install --legacy-peer-deps- Set up environment variables:
cp .env.example .env- Initialize the database:
npx prisma generate
npx prisma db push- Start the development servers:
npm run dev:allThis will start:
- Next.js dev server on
http://localhost:3000 - WebSocket server on
ws://localhost:1234
Alternatively, run them separately:
# Terminal 1
npm run dev
# Terminal 2
npm run server- Open http://localhost:3000 in your browser
- Navigate to http://localhost:3000/register
- Enter your name, email, and password
- Click "Sign Up"
- Log in to your account
- Click "Create New Document" on the dashboard
- Enter a document title
- Start editing!
- Open a document you own
- Click the "Share" button in the top-right corner
- Choose your sharing method:
- Copy Link: Anyone with the link can view (read-only access)
- Invite by Email: Send invite with specific permissions:
- Editor: Can edit and collaborate in real-time
- Viewer: Can only view (read-only)
- Recipients must have an account to access shared documents
- Share a document with another user
- Both users open the document
- Edit simultaneously - see changes appear instantly
- See active collaborators in the bottom-right corner
- Changes auto-save every 2 seconds
Ctrl/Cmd + B- BoldCtrl/Cmd + I- ItalicCtrl/Cmd + Z- UndoCtrl/Cmd + Shift + Z- Redo- Format using toolbar buttons for headings, lists, quotes, and code
├── app/
│ ├── (auth)/ # Authentication pages
│ ├── dashboard/ # Dashboard page
│ ├── document/[id]/ # Editor page
│ ├── api/ # API routes
│ ├── layout.tsx # Root layout
│ └── providers.tsx # Client providers
├── components/
│ ├── editor/ # Editor components
│ ├── ui/ # UI components
│ └── shared/ # Shared components
├── lib/
│ ├── db/ # Database client
│ ├── auth/ # Auth configuration
│ ├── yjs/ # Yjs utilities
│ └── utils/ # Utility functions
├── server/
│ └── websocket-server.js # WebSocket server
├── prisma/
│ └── schema.prisma # Database schema
└── types/ # TypeScript types
POST /api/auth/register- Register new userPOST /api/auth/[...nextauth]- NextAuth.js handler (sign in/out)
GET /api/documents- Get all user documents with permissionsPOST /api/documents- Create new documentGET /api/documents/[id]- Get document by ID with access controlPATCH /api/documents/[id]- Update document (title/content)DELETE /api/documents/[id]- Delete document (owner only)POST /api/documents/[id]/share- Share document with user by email
- id, name, email, password, image, timestamps
- id, title, content, ownerId, timestamps
- id, documentId, userId, role (owner/editor/viewer)
- PostgreSQL database (replace SQLite in production)
- WebSocket server hosting
- Next.js hosting (Vercel, AWS, etc.)
- Update database provider in
prisma/schema.prisma:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}- Set production environment variables:
DATABASE_URL="your-postgres-connection-string"
NEXTAUTH_SECRET="your-secure-random-secret"
NEXTAUTH_URL="https://your-domain.com"
NEXT_PUBLIC_WS_URL="wss://your-websocket-server.com"-
Deploy WebSocket server separately (AWS EC2, DigitalOcean, etc.)
-
Deploy Next.js app to Vercel:
npm run build
vercel --prod- CRDT: Conflict-free replicated data type for efficient collaboration
- Debounced Autosave: Saves every 2 seconds to reduce server load
- IndexedDB: Local persistence for instant loading and offline support
- Lazy Loading: Components and routes are code-split automatically
- Password hashing with bcrypt
- JWT-based session management
- Role-based access control
- CSRF protection with NextAuth
- SQL injection prevention with Prisma
Database: SQLite file at prisma/dev.db
- Stores users, documents, and permissions
- Access with:
npx prisma studio ⚠️ Important: This is a local file - not shared across deployments
WebSocket Server: In-memory state
- Keeps Yjs CRDT state for 1 hour after last user disconnects
- Lost on server restart (documents reload from database)
Browser: IndexedDB cache
- Local copy for offline editing
- Auto-syncs when reconnected
✅ Protected:
- Passwords hashed with bcrypt
- JWT session tokens
- Role-based access control
.gitignoreprevents committing database
- SQLite database is a file (can be copied)
- No encryption at rest
- WebSocket has basic authentication
- For production, use PostgreSQL + proper auth
- Refresh both browser windows to reconnect WebSocket
- Check WebSocket server is running:
npm run server - Check browser console for connection errors
- Verify
NEXT_PUBLIC_WS_URL=ws://localhost:1234in.env
- Ensure you've saved the document (wait for "Saved" indicator)
- Refresh the shared user's browser
- Check they have proper permissions in database:
npx prisma studio
- Ensure the WebSocket server is running on port 1234
- Kill existing process:
lsof -ti:1234 | xargs kill -9 - Restart:
npm run server - Check firewall settings
- Regenerate Prisma client:
npx prisma generate - Sync schema:
npx prisma db push - View data:
npx prisma studio
- Clear build cache:
rm -rf .next - Reinstall dependencies:
rm -rf node_modules && npm install --legacy-peer-deps - Check Node.js version (requires 18+)
Sai Niranjan Nallam
Contributions are welcome! Please open an issue or submit a pull request.
For issues and questions, please open a GitHub issue.