Redis client configuration
The Redis client is initialized from environment variables:src/lib/redis.ts
UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN from the environment.
Key structure
Private Chat uses three primary key patterns:- meta:{roomId}
- messages:{roomId}
- history:{roomId}
Stores room metadata including connected users and creation timestamp.Type: Redis HashExample key:
meta:ABC123xyzData structures
meta: (Hash)
Contains room configuration and connection state. Schema:Creating a room
Creating a room
src/app/api/[[...slugs]]/route.ts
connected array is empty. Users are added when they join.Adding a user to a room
Adding a user to a room
src/proxy.ts
connected array. Maximum 2 tokens allowed.Checking if a user can join
Checking if a user can join
src/proxy.ts
Validating user auth
Validating user auth
src/app/api/[[...slugs]]/auth.ts
messages: (List)
Stores all messages for a room in chronological order. Item schema:src/types/message.ts
The
token field is stored with each message to identify the author, but is only returned to the original sender when fetching messages.Sending a message
Sending a message
src/app/api/[[...slugs]]/route.ts
rpush, then the TTL is synchronized across all keys.Fetching message history
Fetching message history
src/app/api/[[...slugs]]/route.ts
lrange(key, 0, -1) fetches all items in the list from start to end. The token is filtered so users only see their own.Deleting all messages
Deleting all messages
src/app/api/[[...slugs]]/route.ts
TTL management
All keys have time-to-live (TTL) configured to ensure automatic cleanup.Default TTL
src/app/api/[[...slugs]]/route.ts
Setting initial TTL
When a room is created:Synchronizing TTL across keys
When a new message is sent, the TTL is synchronized to prevent keys from expiring at different times:src/app/api/[[...slugs]]/route.ts
- All keys for a room expire at the same time
- No orphaned data remains in Redis
- The meta key acts as the source of truth for TTL
Fetching TTL from the client
The frontend displays a countdown timer based on the TTL:src/app/api/[[...slugs]]/route.ts
redis.ttl(key) returns the remaining seconds before expiration. Returns -1 if the key has no TTL, and -2 if the key doesn’t exist.Expiry behavior
When TTL reaches 0:- Redis automatically deletes all expired keys
- Future requests to the room will fail with “room-not-found-404”
- The middleware redirects users attempting to access the expired room
src/proxy.ts
Key cleanup strategies
- Automatic expiry
- Manual deletion
- Orphan prevention
Redis automatically deletes keys when their TTL expires. This is the primary cleanup mechanism.
Data flow diagram
Redis commands reference
Here are all Redis commands used in Private Chat:| Command | Purpose | Example |
|---|---|---|
hset | Set hash field | redis.hset('meta:roomId', { connected: [] }) |
hgetall | Get all hash fields | redis.hgetall('meta:roomId') |
hget | Get single hash field | redis.hget('meta:roomId', "connected") |
rpush | Append to list | redis.rpush('messages:roomId', message) |
lrange | Get list range | redis.lrange('messages:roomId', 0, -1) |
expire | Set TTL | redis.expire('meta:roomId', 600) |
ttl | Get remaining TTL | redis.ttl('meta:roomId') |
exists | Check if key exists | redis.exists('meta:roomId') |
del | Delete key | redis.del('meta:roomId') |
All commands are executed via the Upstash Redis REST API, making them compatible with serverless environments like Vercel Edge Functions.