This guide outlines the steps to deploy Mem0 with Cloudflare D1 for persistent storage, making your memories accessible from any device.
graph TD
A[Client Devices] --> B[Cloudflare DNS]
B --> C[Cloudflare Pages]
C --> D[Cloudflare Workers]
D --> E[Cloudflare D1]
subgraph "Memory Storage"
E --> F[SQLite Database]
F --> G[Automatic Backups]
end
- Cloudflare account
- Domain name configured with Cloudflare DNS
- Node.js installed locally
- Wrangler CLI (
npm install -g wrangler
) - OpenAI API key
- Login to Wrangler:
wrangler login
- Create a new D1 database:
wrangler d1 create mem0-db
- Create the database schema:
CREATE TABLE memories (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
content TEXT NOT NULL,
embedding JSON,
metadata JSON,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_user_id ON memories(user_id);
CREATE INDEX idx_created_at ON memories(created_at);
Create or update wrangler.toml
:
name = "mem0-api"
main = "src/worker.js"
compatibility_date = "2024-03-09"
[vars]
OPENAI_API_KEY = "your-openai-api-key"
[[d1_databases]]
binding = "DB"
database_name = "mem0-db"
database_id = "your-database-id"
Create src/worker.js
:
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
// CORS headers for cross-origin access
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
// Handle CORS preflight
if (request.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
if (url.pathname === '/memories' && request.method === 'POST') {
const { text, user_id } = await request.json();
// Store memory
await env.DB.prepare(
'INSERT INTO memories (id, user_id, content) VALUES (?, ?, ?)'
).bind(crypto.randomUUID(), user_id, text)
.run();
return new Response(JSON.stringify({ success: true }), {
headers: { 'Content-Type': 'application/json', ...corsHeaders },
});
}
if (url.pathname === '/memories/search' && request.method === 'POST') {
const { query, user_id } = await request.json();
// Search memories
const memories = await env.DB.prepare(
'SELECT content FROM memories WHERE user_id = ? AND content LIKE ?'
).bind(user_id, `%${query}%`)
.all();
return new Response(JSON.stringify(memories.results), {
headers: { 'Content-Type': 'application/json', ...corsHeaders },
});
}
return new Response('Not Found', { status: 404 });
},
};
Create index.html
:
<!DOCTYPE html>
<html>
<head>
<title>Mem0</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100 p-4">
<div class="max-w-lg mx-auto space-y-4">
<div class="bg-white p-4 rounded shadow">
<input type="text" id="memory" placeholder="Enter memory"
class="w-full p-2 border rounded mb-2">
<button onclick="addMemory()"
class="w-full bg-blue-500 text-white p-2 rounded">
Add Memory
</button>
</div>
<div class="bg-white p-4 rounded shadow">
<input type="text" id="search" placeholder="Search memories"
class="w-full p-2 border rounded mb-2">
<button onclick="searchMemories()"
class="w-full bg-green-500 text-white p-2 rounded">
Search
</button>
</div>
<div id="results" class="bg-white p-4 rounded shadow"></div>
</div>
<script>
const API_URL = 'https://api.yourdomain.com';
const USER_ID = localStorage.getItem('user_id') ||
crypto.randomUUID();
// Store user_id for consistent access
localStorage.setItem('user_id', USER_ID);
async function addMemory() {
const memory = document.getElementById('memory').value;
try {
const response = await fetch(`${API_URL}/memories`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
text: memory,
user_id: USER_ID
})
});
const result = await response.json();
if (result.success) {
alert('Memory added successfully!');
document.getElementById('memory').value = '';
}
} catch (error) {
console.error('Error:', error);
alert('Failed to add memory');
}
}
async function searchMemories() {
const query = document.getElementById('search').value;
try {
const response = await fetch(`${API_URL}/memories/search`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
query: query,
user_id: USER_ID
})
});
const results = await response.json();
document.getElementById('results').innerHTML = results
.map(r => `<div class="border-b p-2">${r.content}</div>`)
.join('');
} catch (error) {
console.error('Error:', error);
alert('Failed to search memories');
}
}
</script>
</body>
</html>
- Deploy the Worker:
wrangler deploy
-
Deploy the frontend to Cloudflare Pages:
- Connect your GitHub repository
- Configure build settings (none needed for static site)
- Set environment variables:
- API_URL: https://api.yourdomain.com
-
Configure DNS:
- Add A record for api.yourdomain.com pointing to your Worker
- Add CNAME record for www pointing to your Pages deployment
- Visit your deployed frontend (https://yourdomain.com)
- Add a test memory
- Search for the memory
- Try accessing from different devices
- Monitor usage in Cloudflare dashboard
- Check D1 storage limits
- Review Workers usage metrics
- Backup database regularly (automatic with D1)
- Add authentication if needed:
// Add to worker.js
async function authenticate(request) {
const authHeader = request.headers.get('Authorization');
if (!authHeader) {
throw new Error('No authorization header');
}
// Implement your authentication logic
}
- Rate limiting:
// Add to worker.js
const RATE_LIMIT = 100; // requests per minute
const rateLimiter = new Map();
function checkRateLimit(ip) {
const now = Date.now();
const userRequests = rateLimiter.get(ip) || [];
const recentRequests = userRequests.filter(time => now - time < 60000);
if (recentRequests.length >= RATE_LIMIT) {
throw new Error('Rate limit exceeded');
}
recentRequests.push(now);
rateLimiter.set(ip, recentRequests);
}
- Enable security headers:
// Add to response headers
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block'
-
Implement additional features:
- Full-text search
- Memory categorization
- Media attachments
- Sharing capabilities
-
Add monitoring:
- Set up Cloudflare Analytics
- Configure error tracking
- Monitor API usage
-
Enhance security:
- Add user authentication
- Implement API key rotation
- Set up backup strategy