Cortex is a multi-service stack (Kafka, Neo4j, Redis, API, pipeline worker, dashboard). The dashboard is static (Vercel or Cloudflare Pages); the API runs on Render/Railway/etc.
$0 portfolio deploy: see DEPLOY-FREE.md — Cloudflare Pages + Render free + Aura + Upstash (no Kafka).
| Component | Host | Notes |
|---|---|---|
| Dashboard | Cloudflare Pages or Vercel (frontend/) |
CF: VITE_API_URL; Vercel: CORTEX_API_ORIGIN middleware |
| API | Railway / Render / Fly | api/Dockerfile |
| pipeline-worker | Same as API | pipeline/Dockerfile |
| Neo4j | Neo4j Aura | Bolt URI in env |
| Redis | Upstash | Query cache |
| Kafka | Upstash Kafka / Confluent Cloud | Event bus |
Do not deploy the Python API on Vercel. If the build log shows Using Python 3.12 from pyproject.toml or installs uv.lock, Vercel is treating the repo as FastAPI — that bundle (~5 GB) exceeds Lambda limits.
Fix (pick one):
| Approach | Settings |
|---|---|
| Recommended | Project Settings → General → Root Directory → frontend → Save → Redeploy |
| Repo root | Keep Root Directory . — root vercel.json + .vercelignore upload only frontend/ (excludes Python/api/ so the bundle stays under Vercel limits) |
After changing Root Directory, clear the Framework Preset override if it still says FastAPI — it should be Vite or Other.
Project settings (Root Directory = frontend)
- Root Directory:
frontend - Framework: Vite
- Build:
npm run build - API proxy:
middleware.tsreadsCORTEX_API_ORIGINat runtime (Vercel parsesvercel.jsonbefore build — build-time rewrites cannot inject env vars)
Environment variables
| Variable | Purpose |
|---|---|
CORTEX_API_ORIGIN |
Public API URL — Edge Middleware proxies /query, /health, etc. server-side |
VITE_API_URL |
Do not point at loca.lt — causes 511 tunnel interstitial errors |
Do not import the repo root with Framework Preset FastAPI. That installs the full uv.lock (~5 GB) and exceeds Lambda limits.
cd frontend
npx vercel deploy --prodSet CORTEX_API_ORIGIN=https://your-api.example.com in the Vercel project before deploy.
make demo
open http://localhost:3000 # dashboard (nginx → API)
open http://localhost:8000/docsFor short-lived public demos while the API runs locally:
cloudflared tunnel --url http://localhost:8000
# Set CORTEX_API_ORIGIN to the trycloudflare.com URL on Vercel, redeploy frontendPrefer cloudflared over localtunnel — localtunnel returns 511 for browser fetch() calls.
See DATA_SOURCES.md for local-dev vs oss-* workspaces.
python scripts/seed_demo.py --workspace local-dev
python scripts/import_github_org.py --org tiangolo --repo fastapi --dry-run
make verify-dualDeploy only the API — not Kafka or the pipeline worker. Pre-seed Neo4j with scripts/seed_demo.py so /query works without live ingestion.
# Install CLI: https://docs.railway.com/guides/cli
railway login
railway init # link this repo
railway up # uses railway.toml → api/DockerfileRequired environment variables (Railway → Variables):
| Variable | Example |
|---|---|
NEO4J_URI |
neo4j+s://xxxx.databases.neo4j.io |
NEO4J_USER |
neo4j |
NEO4J_PASSWORD |
Aura password |
REDIS_URL |
rediss://default:token@host.upstash.io:6379 |
CORTEX_API_KEYS |
demo-readonly:authenticated (optional abuse control) |
CORTEX_SEMANTIC_ENABLED |
false |
CORTEX_SEED_DEMO |
true first deploy only — then set false so restarts skip re-seed |
Copy the public Railway URL (e.g. https://cortex-api-production.up.railway.app), set CORTEX_API_ORIGIN on Vercel, and redeploy the frontend.
Production startup: scripts/start_api_production.sh runs migrations on every boot. Demo seed runs only when CORTEX_SEED_DEMO=true.
Use render.yaml as a Blueprint, or create a Web Service with Docker runtime and api/Dockerfile as the Dockerfile path. Same env vars as Railway.
Option A — first Railway deploy: set CORTEX_SEED_DEMO=true on the API service, deploy once, then set CORTEX_SEED_DEMO=false.
Option B — from laptop with Neo4j credentials in .env:
export NEO4J_URI=neo4j+s://...
export NEO4J_USER=neo4j
export NEO4J_PASSWORD=...
uv run python graph/migrate.py
uv run python scripts/seed_demo.py --workspace local-dev --scale small
uv run python scripts/import_github_graph.py --org tiangolo --repo fastapi --workspace oss-tiangolo-fastapi --limit 30
make verify-dual-productionDirect graph import (no Kafka): scripts/import_github_graph.py.
See AURA_MIGRATION.md. Rotate passwords after any credential exposure — update Railway env vars only, never commit secrets.
For public demos, use a read-only key so anonymous traffic cannot hammer write endpoints:
CORTEX_API_KEYS=demo-readonly:authenticatedDashboard users paste the key in Connection settings. Open /query and /health remain usable without a key when CORTEX_API_KEYS is unset.
# Vercel project → Settings → Environment Variables
CORTEX_API_ORIGIN=https://your-api.railway.app
cd frontend && npx vercel deploy --prodVerify:
curl -s https://your-vercel-app.vercel.app/health
curl -s -X POST https://your-vercel-app.vercel.app/query \
-H "Content-Type: application/json" \
-d '{"query":"Why CockroachDB?","workspace_id":"local-dev","limit":5}'CORTEX_API_KEYS=preview-key:admin;authenticated
CORTEX_DEMO_API_KEY=preview-keymake demo and scripts/demo.sh send Authorization when these are set.
Full ingestion uses Kafka + pipeline-worker locally. For cloud v1 without Kafka, use direct graph import:
make import-oss-graph # real GitHub PRs → Neo4j
make seed-oss-fastapi # synthetic OSS demo fallbackFuture v2: deploy pipeline-worker as a second Railway service + Upstash Kafka, or add POST /webhooks/github → synchronous extract/write for demo scale. See LAUNCH.md.