The Problem Sixteen different free‑tier LLM providers each require their own SDK, rate‑limit handling, and error‑mapping. Managing keys, fall‑over, and per‑provider budgets is tedious and error‑prone. FreeLLMAPI collapses all of them behind a single OpenAI‑compatible /v1/chat/completions endpoint so any client library can speak one URL.
What This Does FreeLLMAPI is a proxy built on Express (server) and React/Vite (client). It stores provider keys encrypted in a SQLite database (server/src/db/index.ts) and uses a router (server/src/services/router.ts) to pick the best available model per request, fall‑over on rate‑limit, and track usage against each provider’s free‑tier cap. The router consults the hub module server/src/db/index.ts (45 importers, instability 0.02) for key lookup and usage stats. An oversized proxy handler lives in server/src/routes/proxy.ts (708 lines) and the migration script in server/src/db/migrations.ts (708 lines) – both are high‑churn, high‑blast‑radius files that would benefit from splitting into smaller units. The call graph shows cn (43 call sites), getDb (38), and apply (23) as the most‑touched functions; a change to the database schema ripples through many modules.
How It Is Wired
- Entry point:
maininserver/src/index.ts:12reaches 87 functions, called from 1 place. - Database hub:
initDb→migrateDbSchema→createTables(server/src/db/index.ts) sets up the SQLite schema and performs crypto‑key initialization (server/src/lib/crypto.ts). - Routing flow:
routeRequest→isGatedApiPath→getSessionKey→getStickyModel→ provider‑specific HTTP call (fetchWithTimeout). - Key operations:
getUnifiedApiKey,regenerateUnifiedKey,decryptall touch the DB (server/src/db/index.ts) and crypto (server/src/lib/crypto.ts). - Blast‑radius modules:
server/src/db/index.ts(45 dependents),server/src/app.ts(20 dependents, instability 0.39), andserver/src/lib/crypto.ts(13 dependents, instability 0). - External touches: 60 functions read/write the DB; 1 function calls a model for inference; 8 perform crypto/secret ops. No model inference occurs inside the repo; calls exit the process via the provider HTTP layer.
How To Use It
| Step | Command / File |
|---|---|
| Clone | git clone https://github.com/moses-y/freellmapi |
| Install | cd freellmapi && npm ci (lockfile‑driven install) |
| Env | Copy .env.example → .env; set UNIFIED_DB_PATH, provider API keys (e.g., GOOGLE_API_KEY, GROQ_API_KEY). The unified key is stored encrypted in server/src/db/index.ts. |
| Build/Docker | docker build -t freellmapi . (Dockerfile present) or docker-compose up --build |
| Start server | npm run start (runs server/src/index.ts → main) |
| Start client | npm run dev in client/ (Vite dev server, connects to http://localhost:3000 by default) |
| Desktop | npm run build then npm run start in desktop/ (Electron, entry desktop/src/main.ts) |
Real‑World Use A team wants to prototype a chatbot using multiple free models without managing sixteen SDKs. They add keys for Google Gemini, Groq Llama 3, and OpenRouter, point their OpenAI‑compatible client (openai npm package) at http://localhost:3000/v1/chat/completions, and the router automatically selects the cheapest‑available model, falls back on the next provider when rate‑limited, and logs per‑key token usage to stay under each free‑tier cap.
Code Health & Issues (measured findings, not opinion)
- [HIGH] Pin GitHub Actions to commit SHAs –
.github/workflows/ci.ymluses@v3/@v5tags fordocker/setup-buildx-action,docker/login-action,docker/metadata-action,docker/build-push-action. Tags can move, risking secret exposure. Fix: replace with 40‑character SHAs and let Dependabot bump them. - [MEDIUM] Declare least‑privilege GITHUB_TOKEN permissions – one workflow declares no
permissions. Fix: addpermissions: contents: readat top and widen per‑job as needed. - [MEDIUM] Enable Dependabot or Renovate – 5 manifests, no update bot configured. Fix: commit
.github/dependabot.ymlcovering npm and GitHub Actions. - [MEDIUM] Install from lockfile in CI –
npm installwithout--ci. Fix: usenpm ci(oryarn install --immutable). - [MEDIUM] Gate PRs on dependency vulnerability scan – no scan in CI. Fix: add
dependency-review-actiononpull_requestorosv-scanneron push. - [MEDIUM] Gate
checkoutonpersist-credentials: false– token remains in.git/configfor later steps. Fix: addwith: persist-credentials: falseand pass explicit token only to push steps. - [LOW] Set
timeout-minuteson workflow jobs – 2 jobs have no timeout. Fix: add realistictimeout-minutesper job. - [LOW] Add convention files – missing
.editorconfig,.gitattributes, formatter config. Fix: add those files per project conventions.
The Bottom Line FreeLLMAPI delivers a pragmatic solution for experimenting with many free LLM tiers behind a single OpenAI‑compatible API. The architecture is clear: a hub DB module, a router, and encrypted key storage. However, the codebase shows several high‑impact maintainability risks—oversized proxy/migration files, untagged GitHub Actions, and missing Dependabot. It’s well‑suited for personal or small‑team prototyping where the free‑tier aggregation outweighs the need for rock‑solid production hardening; for larger deployments, invest in the listed hygiene fixes and consider splitting the proxy and migration logic into smaller, testable units.