Upstash Redis — SKILL.md

Raw skill file that agents receive when using this skill

Download
---
name: "Upstash Redis"
description: "Skill for Upstash Redis — auto-generated from documentation"
version: "1.0.0"
author: "skynet"
category: "infrastructure"
agents: ["claude-code", "codex", "gemini"]
tags: ["upstash-redis", "infrastructure", "auto-generated"]
---

# Upstash Redis

---
name: "Upstash Redis"
description: "Use when you need serverless Redis for caching, session storage, rate limiting, or real-time applications. Ideal for edge computing, serverless functions, and applications requiring low-latency data access."
category: infrastructure
metadata:
  author: skynet
  version: 1.0.0
---

# Upstash Redis

Serverless Redis service for modern applications with per-request pricing and global edge locations.

## Setup

### Create Database
```bash
# Install Upstash CLI
npm install -g @upstash/cli

# Login to Upstash
upstash auth login

# Create new Redis database
upstash redis create --name my-redis-db --region global

# List databases
upstash redis list

# Get connection details
upstash redis show my-redis-db
```

### Environment Configuration
```bash
# .env file
UPSTASH_REDIS_REST_URL=https://your-db.upstash.io
UPSTASH_REDIS_REST_TOKEN=your-token
```

## Client Integration

### Node.js with @upstash/redis
```javascript
import { Redis } from '@upstash/redis'

// Initialize client
const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL,
  token: process.env.UPSTASH_REDIS_REST_TOKEN,
})

// Basic operations
await redis.set('key', 'value')
const value = await redis.get('key')
await redis.del('key')

// With expiration
await redis.setex('session:123', 3600, JSON.stringify({userId: 456}))

// Increment counter
await redis.incr('page:views')
```

### Python with upstash-redis
```python
from upstash_redis import Redis
import os

# Initialize client
redis = Redis(
    url=os.getenv('UPSTASH_REDIS_REST_URL'),
    token=os.getenv('UPSTASH_REDIS_REST_TOKEN')
)

# Basic operations
redis.set('key', 'value')
value = redis.get('key')
redis.delete('key')

# Hash operations
redis.hset('user:123', {'name': 'John', 'email': 'john@example.com'})
user = redis.hgetall('user:123')
```

### REST API Direct
```bash
# Set key-value
curl -X POST "$UPSTASH_REDIS_REST_URL/set/mykey/myvalue" \
  -H "Authorization: Bearer $UPSTASH_REDIS_REST_TOKEN"

# Get value
curl -X GET "$UPSTASH_REDIS_REST_URL/get/mykey" \
  -H "Authorization: Bearer $UPSTASH_REDIS_REST_TOKEN"

# Pipeline commands
curl -X POST "$UPSTASH_REDIS_REST_URL/pipeline" \
  -H "Authorization: Bearer $UPSTASH_REDIS_REST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[
    ["SET", "key1", "value1"],
    ["SET", "key2", "value2"],
    ["GET", "key1"]
  ]'
```

## Common Use Cases

### Session Store
```javascript
// Store session
const sessionData = {
  userId: 123,
  username: 'john_doe',
  loginTime: Date.now()
}
await redis.setex(`session:${sessionId}`, 3600, JSON.stringify(sessionData))

// Retrieve session
const session = await redis.get(`session:${sessionId}`)
if (session) {
  const userData = JSON.parse(session)
  // Extend session
  await redis.expire(`session:${sessionId}`, 3600)
}
```

### Rate Limiting
```javascript
async function checkRateLimit(userId, maxRequests = 100, windowSeconds = 3600) {
  const key = `rate_limit:${userId}:${Math.floor(Date.now() / (windowSeconds * 1000))}`
  
  const count = await redis.incr(key)
  if (count === 1) {
    await redis.expire(key, windowSeconds)
  }
  
  return {
    allowed: count <= maxRequests,
    remaining: Math.max(0, maxRequests - count),
    resetTime: Math.ceil(Date.now() / 1000) + windowSeconds
  }
}
```

### Caching
```javascript
async function getCachedData(cacheKey, fetchFunction, ttlSeconds = 300) {
  // Try cache first
  const cached = await redis.get(cacheKey)
  if (cached) {
    return JSON.parse(cached)
  }
  
  // Fetch and cache
  const data = await fetchFunction()
  await redis.setex(cacheKey, ttlSeconds, JSON.stringify(data))
  return data
}

// Usage
const userData = await getCachedData(
  `user:${userId}`,
  () => database.users.findById(userId),
  600 // 10 minutes
)
```

### Pub/Sub with EventSource
```javascript
// Publisher
await redis.publish('notifications', JSON.stringify({
  type: 'user_login',
  userId: 123,
  timestamp: Date.now()
}))

// Subscriber (using EventSource)
const eventSource = new EventSource(
  `${process.env.UPSTASH_REDIS_REST_URL}/subscribe/notifications?_token=${process.env.UPSTASH_REDIS_REST_TOKEN}`
)

eventSource.onmessage = (event) => {
  const notification = JSON.parse(event.data)
  console.log('Received:', notification)
}
```

## Advanced Operations

### Lua Scripts
```javascript
// Atomic increment with max value
const script = `
local current = redis.call('GET', KEYS[1])
local max = tonumber(ARGV[1])
if current == false then
  redis.call('SET', KEYS[1], 1)
  return 1
end
current = tonumber(current)
if current >= max then
  return -1
end
redis.call('INCR', KEYS[1])
return current + 1
`

const result = await redis.eval(script, ['counter'], [100])
```

### Geospatial Operations
```javascript
// Add locations
await redis.geoadd('locations', 
  -122.4194, 37.7749, 'San Francisco',
  -74.0060, 40.7128, 'New York'
)

// Find nearby locations
const nearby = await redis.georadius('locations', -122.4194, 37.7749, 1000, 'km', 'WITHDIST')
```

## Database Management

### Monitoring
```bash
# Get database info
upstash redis info my-redis-db

# View metrics
upstash redis metrics my-redis-db --period 24h

# Monitor real-time
upstash redis monitor my-redis-db
```

### Backup and Restore
```bash
# Export data
upstash redis export my-redis-db --output backup.rdb

# Import data
upstash redis import my-redis-db --file backup.rdb

# Clone database
upstash redis clone my-redis-db --name my-redis-db-staging
```

## Decision Tree

```
Need Redis for your app?
├── High throughput, always-on? → Consider dedicated Redis
├── Serverless/edge computing? → Use Upstash Redis
├── Cost optimization needed? → Use Upstash (pay-per-request)
└── Global distribution? → Use Upstash Global

Choose region:
├── Global users? → Global region (multi-region)
├── US users only? → us-east-1 or us-west-1
├── EU users? → eu-west-1
└── Asia users? → ap-southeast-1

Data persistence needs:
├── Session data? → TTL with auto-expiration
├── Cache only? → No persistence needed
├── Analytics? → Use append-only data structures
└── Critical data? → Enable daily snapshots
```

## Troubleshooting

### Connection Issues
```
Error: "Connection timeout"
```
**Fix:**
```javascript
// Increase timeout
const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL,
  token: process.env.UPSTASH_REDIS_REST_TOKEN,
  timeout: 10000 // 10 seconds
})
```

### Authentication Errors
```
Error: "Invalid token"
```
**Fix:**
```bash
# Regenerate token
upstash redis reset-token my-redis-db

# Update environment variables with new token
```

### Rate Limiting
```
Error: "Rate limit exceeded"
```
**Fix:**
```javascript
// Implement exponential backoff
async function redisWithRetry(operation, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await operation()
    } catch (error) {
      if (error.message.includes('rate limit') && i < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000))
        continue
      }
      throw error
    }
  }
}
```

### Memory Issues
```
Error: "Memory usage exceeded"
```
**Fix:**
```javascript
// Set TTL on all keys
await redis.expire('key', 3600)

// Clean up expired keys
await redis.scan(0, 'MATCH', 'temp:*').then(keys => {
  if (keys[1].length > 0) {
    return redis.del(...keys[1])
  }
})

// Use memory-efficient data structures
await redis.hset('user:123', field, value) // Instead of separate keys
```

### Performance Optimization
```javascript
// Use pipeline for bulk operations
const pipeline = redis.pipeline()
for (let i = 0; i < 1000; i++) {
  pipeline.set(`key:${i}`, `value:${i}`)
}
await pipeline.exec()

// Batch operations
const results = await Promise.all([
  redis.get('key1'),
  redis.get('key2'),
  redis.get('key3')
])
```

curl -s https://skills.skynet.ceo/api/skills/upstash-redis/skill.md