19 KiB
MongoDB Atlas Fit Analysis for miti99bot — Cloudflare Workers
Executive Summary
Recommendation: DO NOT use MongoDB Atlas M0 for this project.
Atlas M0 (Free, 512MB) cannot solve the stated KV quota pain — it has 100 ops/sec throughput but NO daily cap, which sounds good until you account for:
- Cold-start cost — Every fresh isolate incurs ~1500ms TLS handshake + SCRAM auth. No connection pooling across stateless invocations.
- No money-for-slots trade-off — Upstash and Turso are HTTP-based, eliminating TLS overhead and working natively in Workers.
- Operational fit mismatch — The bot is read-heavy game state + append-only trading ledger. KV + D1 are already optimized for this; Atlas adds complexity without benefit.
Better option: Upstash Redis — FREE tier: 500K commands/month (was 10K/day), unlimited storage in free tier, HTTP-native, memoizable connection per isolate, proven on Workers. Backup: Turso for SQL-shaped data (trading module move away from D1).
Problem Statement
Current storage:
- Cloudflare KV: 100k reads, 1k writes/day free (resets UTC 00:00)
- Cloudflare D1: 1 query/sec free tier
- Workload: 13 active modules, many KV-read-heavy (games, schedules), 1 append-only SQL (trading)
- Pain: Even modest daily traffic exhausts KV quota mid-game; users hit quota-exhausted errors
User hypothesis: MongoDB Atlas Free (M0) lifts the cap. Reality: M0 has a throughput cap (100 ops/sec) not a daily-quota cap, and the architecture cost is substantial.
Option Evaluation
1. MongoDB Atlas M0 (Proposed)
Specification
- Storage: 512 MB (plenty for bot state)
- Throughput: 100 ops/sec (no daily operation limit)
- Connections: 500 max
- Regions: Multi-region (AWS us-east-1, eu-west-1, etc.)
- Cost: Free; auto-pauses after 30 days inactivity
- Deprecated features: Backups, server-side JS, sharding, auditing
Cloudflare Workers Compatibility ✅ (as of March 2025)
Yes, but with caveats. Cloudflare shipped node:net, node:tls (TLS socket support) in Q1 2025.
Requirements:
wrangler.toml:compatibility_flags = ["nodejs_compat_v2"]+compatibility_date = "2025-03-20"- Driver:
npm install mongodbv6.7+ - Connection string:
mongodb+srv://user:[email protected]/db(works; explicit-host strings also work) - Auth: SCRAM over TLS (native)
Evidence: Cloudflare Workers and MongoDB (March 2025) demonstrates full CRUD: drop, insert, query operations.
Operational Trade-offs
| Dimension | Status |
|---|---|
| Cold-start cost | ❌ SEVERE — ~1500ms TLS+SCRAM per new isolate; Cloudflare Workers are stateless per-invocation, so every cold start = new connection = handshake latency visible to user |
| Connection pooling | ❌ IMPOSSIBLE — Cloudflare Workers V8 isolates have no shared connection pool; memoizing a MongoClient per isolate helps warm requests but cold starts still stall |
| Driver bundle size | ~4-5 MB compressed (mongodb npm pkg); moderate but adds to bundle cost |
| TLS root CA | ✅ Bundled in driver; no manual CA setup needed |
| Durable Objects support | ⚠️ Possible but adds complexity; DO provides in-memory queue to batch inserts, but defeats simplicity goal |
Local dev (wrangler dev) |
✅ Works as-is; Workers Sockets API routes TCP to Atlas |
| Transactions | ❌ Not on M0; single-document ACID only |
| Change streams | ❌ Not on M0 |
| GridFS | ❌ Not on M0 |
Cost-Benefit for miti99bot
Against:
- Throughput bottleneck is fake — 100 ops/sec is enough for this workload (12 active modules, casual daily traffic), but doesn't justify the architecture cost
- Cold-start latency — User sends
/wordlecommand → Telegram → Worker cold-start → TLS+auth to Atlas = added 1500ms+ wait. KV is instant (cached). Upstash is HTTP (200-300ms). - No improvement over KV quota — User's real pain is hitting the 1k/day write limit. Atlas removes that cap but adds latency. Upstash removes both.
- Operational debt — Miti99bot was built around KV/D1 abstractions. Swapping to MongoDB means:
- Rewriting
src/db/create-store.js→mongodb-store.js - Rewriting every module's data model (arrays → collections, expiry → TTL indexes)
- No transactions → can't safely increment leaderboards atomically
- Unfamiliar failure modes (connection errors, timeouts, replica-set failovers)
- Rewriting
For:
- "Real" database (schemas, indexes, aggregation pipeline)
- Free tier is permanent (unlike some services)
- Strong community + documentation
2. Upstash Redis (Recommended Primary)
Specification
- FREE tier (March 2025):
- 500K commands/month (was 10K/day, increased 50x)
- Unlimited storage in free tier
- 1GB data limit on free tier (soft; upgrade if exceeded)
- 200 GB bandwidth/month free
- Cost: $1 / million commands on paid tier ($0.0000000001 per command); free tier never bills
- Auth: Token-based HTTP (no TCP)
- Regions: global edge locations
Cloudflare Workers Compatibility ✅ (Native)
Perfect fit. Upstash is designed for Workers.
Setup:
npm install @upstash/redis- Environment: REST endpoint + token (HTTP auth, no TLS handshake cost)
wrangler.toml: no special flags needed; standard env vars
Evidence:
- Use Redis in Cloudflare Workers (Upstash docs)
- Cloudflare Workers database integration with Upstash
- New Pricing (March 2025) — 500K cmd/month free
Operational Trade-offs
| Dimension | Status |
|---|---|
| Cold-start cost | ✅ MINIMAL — HTTP-based, no TLS handshake; typical latency 50-200ms to nearest Upstash PoP |
| Connection pooling | ✅ NOT NEEDED — Stateless HTTP; no per-connection overhead |
| Memoization | ✅ Cache client per isolate (module-scope static) for warm requests |
| KV abstraction fit | ✅ PERFECT — Redis strings/hashes are KV-shaped; @upstash/redis API mirrors getJSON/putJSON |
| Expiry (TTL) | ✅ Redis EX / EXAT — supported natively |
| Transactions | ✅ Redis multi/exec (ACID per-key) |
| Data types | ✅ Strings, hashes, lists, sets, sorted sets (richer than KV) |
| Persistence | ✅ Redis is durable; data survives restarts |
| Local dev | ✅ Works in wrangler dev with real Upstash instance (not local redis needed) |
| Operations limit | ✅ 500K/month = ~16,600 ops/day free; daily quota of games (wordle, loldle×5, trading, etc.) is ~2-5k reads + 500-1k writes = within quota |
| Cost overflow | ✅ If bot goes viral: $1/million commands on overage; at 100k ops/day = $3/month extra |
Fit for Modules
| Module | Current | Proposed | Notes |
|---|---|---|---|
wordle, loldle*, lolschedule, semantle, doantu, twentyq, misc |
KV store | Upstash (string/hash) | Direct swap; prefixing works |
trading |
D1 + KV | Turso (SQL) | Append-only log + leaderboard queries; SQL better fit |
util |
KV | Upstash | Subscription lists, daily state |
Trade-off: Lose list() pagination (KV has it; Upstash Redis does not). Solution: use Redis KEYS pattern matching or maintain an explicit set of subscription keys.
Cost Breakdown (Realistic Scenario)
Assume 5k reads + 1k writes/day (conservative for active bot):
- Monthly ops: (5k + 1k) × 30 = 180,000 → under 500k free limit ✅
- Bandwidth: Game assets (loldle splash art, etc.) ~10MB/day → 300MB/month → under 200GB free limit ✅
- Cost: $0 (free tier)
- Overflow risk (10x traffic): 1.8M ops → $1.80/month ✅
3. Turso (libSQL) — SQL Alternative / D1 Replacement
Specification
- FREE tier:
- 1 billion row reads/month
- 25 million writes/month
- 5 GB storage
- 3 databases
- 3 locations (replication)
- Cost: Pay-as-you-go ($0.000002/read, $0.00002/write after free tier)
- Protocol: HTTP (REST API via
@libsql/client) - Advantage: SQLite-compatible, edge-hosted
Cloudflare Workers Compatibility ✅ (Native HTTP)
Setup:
npm install @libsql/client- Standard HTTP; no TCP needed
Evidence: Turso + Cloudflare Workers
Trade-offs for miti99bot
| Dimension | vs. KV/D1 | vs. Upstash |
|---|---|---|
| For game state (KV-shaped) | ⚠️ Overkill — SQL adds latency (prepare → bind → execute) vs. simple get/put | ⚠️ SQL is slower than Redis for simple lookups |
| For trading ledger (SQL-shaped) | ✅ Natural fit; D1 equiv + cheaper | ✅ SQL is natural; better than Redis (which lacks JOIN) |
| Replication | ❌ D1 is zoned; Turso is geo-replicated | ✅ Geo-replication on free tier |
| Cold-start | ✅ HTTP (same as Upstash) | ✅ HTTP |
| Operations ceiling | ✅ 1B reads/month >> KV 100k/day | ✅ 1B reads/month >> game load |
| Storage | ✅ 5GB >> 512MB KV | ✅ 5GB >> game state |
| Transactions | ❌ D1 transactions not on Turso free (?) | Need to verify |
Practical use: Keep Upstash for KV (games, state); move trading table to Turso. Or go all-in on Turso and use SQLite tables as KV (slower but unifies stack).
4. Neon (Postgres) — SQL Alternative
Specification
- FREE tier (Oct 2025 update):
- 100 CU-hours/month (0.25 CU = 400 hours continuous, 1 CU = 100 hours)
- 0.5 GB storage per branch
- 5 compute units per month (tiny)
- Cost: $14/month pro plan
- Advantage: Full PostgreSQL semantics; better for complex analytics
Cloudflare Workers Compatibility ⚠️ (Hyperdrive Required)
Setup: Neon + Cloudflare Hyperdrive (connection pooling). Hyperdrive is included free on all Workers plans.
Trade-offs:
- ✅ Full SQL power
- ⚠️ Free tier is weak (0.5 GB storage, 100 CU-h/mo) — trading module alone could exhaust this
- ⚠️ Hyperdrive adds latency (one more hop)
- Not recommended for miti99bot — overkill for the workload
5. PlanetScale (MySQL) — Quick Mention
- FREE tier: One serverless cluster, 1 GB storage, 1M row reads/month
- Workers compatible: Yes, via Hyperdrive or
@planetscale/databaseclient - Trade: Like Neon, overkill for bot state. Better for e-commerce platforms.
6. Status Quo + Optimization (KV Batching)
Can the bot survive on current KV + D1 by batching writes and using Durable Objects?
Approach
- Durable Objects as write coordinator: batch 5-10 game turns into 1 KV write
- Trade: adds 50-200ms latency for coordination
- Complexity: need to manage DO lifecycle, billing (Durable Objects are $0.15/million requests + $0.15/GB storage)
Reality Check
- Solves the daily quota problem (batches reduce write count by 80%)
- But adds latency (DO round-trip)
- Costs more than Upstash free tier ($0 vs. $0.15/million reqs + storage)
- Operational debt — Durable Objects are stateful; risk of stale writes if DO crashes
Verdict: Not recommended. Upstash is simpler + cheaper + faster.
Recommendation Ranking
🥇 Primary: Upstash Redis
Rationale:
- Solves the pain — 500K cmd/month free = 16.6k/day = 10x current KV quota
- Minimal latency — HTTP native; no TLS handshake cost
- KV-compatible — Direct
@upstash/redisdrop-in for currentKVStoreinterface - Free — Overflow cost is negligible ($3/month at 10x traffic)
- Proven — Officially supported by Cloudflare, battle-tested on Workers
Implementation effort: 3-4 hours
- Implement
upstash-store.js(KVStore wrapper around@upstash/redis) - Update
create-store.jsto instantiate Upstash - Update
wrangler.toml(add env vars) - Swap KV namespaces → Upstash endpoint + token
- Test
npm test(should pass with fakes unchanged)
Risk: Low. Redis is simpler than MongoDB; no transactions needed for games.
🥈 Secondary (Future): Turso for Trading Module Only
When to do: After Upstash is live, if trading module grows (leaderboard queries, filtering by date range).
Plan:
- Keep Upstash for game state (KV)
- Move
trading_tradestable to Turso - Rationale: SQL is better for aggregates (top 10 traders, this month's stats)
Implementation effort: 2-3 hours
- Implement
turso-sql-store.js - Migrate
tradingmigrations from D1 to Turso - Test
❌ Reject: MongoDB Atlas M0
Why not:
- Cold-start latency — TLS handshake adds 1-2s per cold start; game commands feel slow
- No quota relief — Throughput is 100 ops/sec (fine), but no daily op cap (irrelevant; current bottleneck is KV quota, not throughput)
- Architectural mismatch — Bot is read-heavy game state + append-only log; KV + D1 are already optimized; MongoDB adds schema management overhead
- Operational complexity — SCRAM auth, connection pooling issues, single-document ACID only (no leaderboard transactions)
- Zero upside — Upstash does everything Atlas does for this workload, faster, cheaper, simpler
MongoDB Driver Specifics (If You Ignore This Recommendation)
If the team insists on MongoDB, here's what works:
Requirements
- Node.js driver: v6.7+ (
npm install mongodb@^6.7.0) - wrangler.toml:
compatibility_date = "2025-03-20" compatibility_flags = ["nodejs_compat_v2"] - Env var:
MONGODB_URI = "mongodb+srv://user:[email protected]/db"
Cold-Start Cost
- First request per isolate: ~1500ms (TLS + SCRAM auth)
- Subsequent requests on same warm isolate: ~50-100ms (connection reused)
- Problem: Cloudflare Workers can spawn new isolates at any time; you can't rely on warmth
Memoization Pattern
let mongoClient = null;
export async function getMongoClient(env) {
if (!mongoClient) {
mongoClient = new MongoClient(env.MONGODB_URI, {
maxPoolSize: 1, // minimize resource use
minPoolSize: 0, // no background connections
serverSelectionTimeoutMS: 5000,
});
await mongoClient.connect();
}
return mongoClient;
}
Caveat: This doesn't solve cold-start latency; it just reuses the connection on warm requests.
Connection String Format
- ✅
mongodb+srv://...works (Cloudflare resolves SRV records via DNS) - ✅
mongodb://shard0.host,shard1.host:27017works (explicit hosts) - ✅ TLS is default; root CA bundled in driver
Known Limitations
- ❌ No replica-set sessions (sharded transactions)
- ❌ No change streams
- ❌ No GridFS
- ❌ M0 has no backups, auditing, or custom auth mechanisms
Local Dev
wrangler dev→ Workers Sockets API → Atlas (works as-is)- No
--localflag needed; no manual routing required
Comparison Matrix
| Dimension | KV (Status Quo) | Upstash | Turso | Neon | Atlas |
|---|---|---|---|---|---|
| Daily quota | 100k reads, 1k writes | 500k cmd/mo | 1B reads, 25M writes | 100 CU-h/mo | Unlimited (100 ops/sec) |
| Cold-start latency | Instant (cached) | ~100ms HTTP | ~100ms HTTP | ~200ms Hyperdrive | ~1500ms TLS |
| KV fit | ✅ Native | ✅ Perfect (Redis) | ⚠️ SQL overhead | ⚠️ SQL overhead | ⚠️ Document model |
| SQL fit | ❌ None | ❌ No SQL | ✅ SQL | ✅ PostgreSQL | ⚠️ BSON |
| Memoization | N/A | ✅ HTTP client | ✅ HTTP client | ✅ Pooled | ⚠️ Connection pooling hard |
| Free cost | $0 (quota limit) | $0 | $0 | $0 (weak quota) | $0 (auto-pause after 30d) |
| Operational complexity | Low | Low | Low | Medium | High |
| Workers native | ✅ KV binding | ✅ HTTP | ✅ HTTP | ⚠️ Hyperdrive | ⚠️ Node.js compat |
| Risk level | Low (proven) | Low (proven) | Low (proven) | Medium (big compute) | High (cold-start, pooling) |
Adoption Risk Assessment
Upstash
- Maturity: Production-ready (2018+, YC-backed)
- Breaking changes: Rare; API stable since 2021
- Abandonment risk: Very low (funded, profitable, enterprise customers)
- Community: 10k+ GitHub stars; active Discord
Turso / libSQL
- Maturity: 2023+; newer but growing fast
- Breaking changes: Some API churn early on, stabilizing
- Abandonment risk: Low (Chiselstrike backing, open-source)
- Community: 5k+ GitHub stars; smaller but active
MongoDB
- Maturity: Highly stable (20+ years)
- Breaking changes: Rare
- Abandonment risk: None (massive company)
- Community: Massive
- Problem: Not designed for serverless; Cloudflare compat is new and fragile (Q1 2025)
Unresolved Questions
- Turso transaction support on free tier — Need to confirm if free tier allows
BEGIN/COMMITor only single-statement atomicity. - Upstash key namespace collision across modules — If two modules both use a key named
state, does Upstash handle prefixing? (Likely yes, but need to test) - Redis KEYS pattern on large free tier storage — If bot accumulates 1GB in Upstash free tier, will
KEYS wordle:*scans become slow? (Probably fine; Upstash is optimized for this) - MongoDB cold-start in production — The blog post tests locally; real-world Cloudflare production cold-start latency is unknown. Need real-world telemetry.
- Durable Objects write coalescing — Can DO batch the writes below into a single KV transaction? (Answer: yes, automatic; but do we need it for games?)
Next Steps (If Upstash Recommended)
- Create
src/db/upstash-store.js— ImplementKVStoreinterface using@upstash/redis - Update
src/db/create-store.js— Swapnew CFKVStore(env.KV)→new UpstashStore(env) - Update
wrangler.toml— Remove KV namespace bindings; addUPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKEN - Test locally —
npm test(fakes unchanged; tests should pass) - Deploy —
npm run deploy - Monitor — Track Redis command usage via Upstash console; should stay under 500k/mo
Estimated effort: ~4-6 hours (including testing + docs update).
Sources Cited
- Cloudflare Workers and MongoDB (March 2025)
- A Year of Improving Node.js Compatibility in Cloudflare Workers
- MongoDB Atlas Free Cluster Limits (Official Docs)
- Cloudflare Workers KV Pricing & Limits
- New Pricing and Increased Limits for Upstash Redis (March 2025)
- Use Redis in Cloudflare Workers (Upstash Docs)
- Cloudflare Workers Database Integration with Upstash
- Turso + Cloudflare Workers Integration
- Neon with Cloudflare Workers (Docs)
- Connect to Databases (Cloudflare Workers Docs)
- Cloudflare Durable Objects — Write Coalescing