A private, real-time, self-destructing messaging platform built with Next.js, Elysia, and Upstash.
- Private Room Creation: Generate unique, secure chat rooms with a single click
- Real-time Messaging: Instant message delivery using Upstash Realtime channels
- Self-Destructing Rooms: Rooms automatically expire after 12 minutes (configurable)
- Manual Destruction: Users can manually destroy rooms at any time, permanently deleting all messages
- User Limit: Maximum 2 users per room for private, one-on-one conversations
- Anonymous Identity: Auto-generated anonymous usernames (e.g.,
anon-lion-abc12) stored in localStorage - Room Link Sharing: Easy room URL copying for quick sharing with another user
- Token-Based Authentication: HTTP-only cookies with secure tokens for room access
- Room Capacity Enforcement: Middleware prevents more than 2 users from joining a room
- Message Privacy: Messages are only visible to authenticated room participants
- Auto-Expiration: All data (messages, room metadata) automatically deleted after TTL expires
- Secure Cookies: HttpOnly, Secure (in production), and SameSite=strict cookie policies
- Live Countdown Timer: Real-time display of remaining room lifetime
- Visual Alerts: Color-coded timer (amber β red) when time is running low
- Error Handling: Clear error messages for room not found, room full, and room destroyed scenarios
- Responsive Design: Clean, modern UI with dark theme optimized for all screen sizes
- Message Timestamps: Messages display time sent (HH:mm format)
- Sender Identification: Distinguishes between "YOU" and other participants with color coding
- Auto-Scroll: Messages automatically scroll to show new content
- Next.js - React framework with App Router
- React - UI library
- TailwindCSS - Utility-first CSS framework
- @tanstack/react-query - Data fetching and state management
- Elysia - Fast, type-safe web framework
- @elysiajs/eden - Type-safe API client for frontend-backend communication
- Upstash Redis - Cloud-native Redis for data storage
- @upstash/realtime - Real-time pub/sub messaging
- Zod - Schema validation (used via Elysia)
meta_room:{roomId}- Room metadata hashconnected: Array of authenticated user tokenscreatedAt: Room creation timestamp- TTL: 12 minutes (720 seconds)
messages:{roomId}- List of messages in the room- Each message contains: id, sender, text, timestamp, roomId, token
- TTL: Synced with room TTL
{roomId}- Additional room data storage- TTL: Synced with room TTL
chat.message- Broadcasted when a new message is sentchat.destroy- Broadcasted when a room is manually destroyed
- POST /api/room/create - Create a new chat room
- Returns:
{ roomId: string }
- Returns:
- GET /api/room/ttl?roomId={roomId} - Get remaining room lifetime
- Returns:
{ ttl: number }(seconds)
- Returns:
- DELETE /api/room?roomId={roomId} - Destroy room immediately
- Emits:
chat.destroyevent - Deletes: All room data and messages
- Emits:
- POST /api/messages?roomId={roomId} - Send a message
- Body:
{ sender: string, text: string } - Validation: sender max 100 chars, text max 1000 chars
- Emits:
chat.messageevent
- Body:
- GET /api/messages?roomId={roomId} - Get all messages in room
- Returns:
{ messages: Message[] } - Note: Token only included for sender's own messages
- Returns:
- GET /api/realtime - WebSocket endpoint for real-time updates
- Handled by Upstash Realtime
- Room Proxy (
src/proxy.ts)- Validates room existence before access
- Enforces 2-user limit per room
- Generates and sets authentication tokens
- Redirects on errors (room not found, room full)
- useUsername - Generates and persists anonymous usernames
- useRealtime - Subscribes to real-time events (chat.message, chat.destroy)
- Node.js 20+ installed
- Upstash account with Redis and Realtime enabled
-
Clone the repository
git clone https://github.com/03aey/realtime-chat cd realtime-chat -
Install dependencies
bun install
-
Configure environment variables Create a
.envfile in the root directory:UPSTASH_REDIS_REST_URL=<your-upstash-redis-url> UPSTASH_REDIS_REST_TOKEN=<your-upstash-redis-token>
Get these credentials from your Upstash Dashboard.
-
Run development server
bun dev
-
Open in browser Navigate to localhost:3000
- Visit the homepage
- Your anonymous identifier is auto-generated and displayed
- Click "Create secure room"
- You'll be redirected to your new room
- In the room, click the "Copy" button next to the Room ID
- Share the URL with the person you want to chat with
- Only 2 users can join a room
- Type your message in the input field
- Press Enter or click "SEND"
- Messages appear instantly for both participants
- Your messages are labeled "YOU" in green
- Other participant's messages are labeled with their identifier in blue
- Click the "Destroy now" button (π£ icon) in the header
- All messages are permanently deleted
- Both users are redirected to the homepage with a "ROOM DESTROYED" notice
- Rooms automatically expire after 12 minutes
- A countdown timer shows remaining time
- When time reaches 0, the room is destroyed
- Users are redirected to homepage with "ROOM DESTROYED" notice
Edit ROOM_TTL_SECONDS in src/app/api/[[...slugs]]/route.ts:
const ROOM_TTL_SECONDS = 12 * 60; // Change this value (in seconds)Edit the ANIMALS array in src/hooks/use-username.ts:
const ANIMALS = [
"Lion",
"Tiger",
"Elephant",
// Add more animals here
];Modify the capacity check in src/proxy.ts:
if (meta.connected.length >= 2) {
// Change 2 to desired limit
return NextResponse.redirect(new URL("/?error=room-full", req.url));
}realtime-chat/
βββ src/
β βββ app/
β β βββ api/
β β β βββ [[...slugs]]/
β β β β βββ route.ts # Main API routes (Elysia)
β β β β βββ auth.ts # Authentication middleware
β β β βββ realtime/
β β β βββ route.ts # Upstash Realtime handler
β β βββ room/
β β β βββ [roomId]/
β β β βββ page.tsx # Chat room UI
β β βββ layout.tsx # Root layout
β β βββ page.tsx # Homepage
β β βββ globals.css # Global styles
β βββ components/
β β βββ providers.tsx # React Query provider
β βββ hooks/
β β βββ use-username.ts # Username generation hook
β βββ lib/
β β βββ eden.ts # API client (Elysia Eden)
β β βββ realtime-client.ts # Realtime client hook
β β βββ realtime.ts # Realtime schema & config
β β βββ redis.ts # Redis client
β βββ proxy.ts # Room access middleware
βββ public/ # Static assets
βββ .env # Environment variables
βββ package.json # Dependencies
βββ tsconfig.json # TypeScript config
βββ next.config.ts # Next.js config
βββ tailwind.config.ts # TailwindCSS config
- No Server-Side Logging: Messages are not logged or stored beyond Redis
- Ephemeral Storage: All data is deleted when room expires or is destroyed
- Token Validation: Each request validates room membership via tokens
- Input Validation: All inputs are validated using Zod schemas
- CORS: Configure CORS for production if needed
- Rate Limiting: Consider adding rate limiting for production use
- Room may have expired (12-minute TTL)
- Room may have been manually destroyed
- Invalid room ID in URL
- Maximum 2 users allowed per room
- Wait for a user to leave or create a new room
- Check Upstash Realtime credentials
- Verify WebSocket connection in browser dev tools
- Ensure
/api/realtimeendpoint is accessible
- Verify
.envfile exists in root directory - Restart development server after adding variables
- Check variable names match exactly