convex-lite
A small backend that speaks the public Convex contract. Write ordinary Convex code, use the unmodified convex@1.46.0 client, and run your frontend anywhere — including localhost. This server hosts your functions and data.
AGENTS.md (plain text of this page) llms.txt live demo source
https://convex.edifear.com/AGENTS.md and follow it top to bottom. It contains the same steps as this page, in plain text.1Project setup
npm install convex@1.46.0
mkdir convex
# the CLI, once per machine
git clone https://github.com/Edifear/convex-lite ~/convex-lite
cd ~/convex-lite && npm ci --ignore-scripts && npm run build
export CONVEX_LITE=~/convex-lite/bin/convex-lite.js
export CONVEX_ADMIN_KEY=... # ask the server owner; needed to push code
2Write functions — standard Convex
convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
todos: defineTable({ text: v.string(), done: v.boolean() }).index("by_done", ["done"]),
});
convex/todos.ts
import { v } from "convex/values";
import { mutation, query } from "./_generated/server";
export const list = query({
args: {},
handler: async (ctx) => ctx.db.query("todos").order("desc").collect(),
});
export const add = mutation({
args: { text: v.string() },
handler: async (ctx, { text }) => ctx.db.insert("todos", { text, done: false }),
});
- Every function declares
argsvalidators; the server enforces them. - Queries are read-only and deterministic (
Date.now()frozen,Math.random()seeded, nofetch). - Mutations are transactions: all writes commit or none. One mutation at a time per app.
- Actions may
fetchand call functions withctx.runQuery/ctx.runMutation/ctx.runAction. internalQuery/internalMutation/internalActionare not callable from clients.- An action that references
api.<sameModule>.<fn>needs an explicit return type (TypeScript circular inference).
3Push and develop
Watch convex/ and push on every change. No local backend is started.
node $CONVEX_LITE dev --url https://convex.edifear.com --dir convex
This generates convex/_generated/ and writes .env.local with CONVEX_URL and VITE_CONVEX_URL=https://convex.edifear.com. One-off deploy:
CONVEX_URL=https://convex.edifear.com node $CONVEX_LITE push --dir convex
4Frontend
import { ConvexProvider, ConvexReactClient } from "convex/react";
const client = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL);
// useQuery(api.todos.list, {}) useMutation(api.todos.add) useAction usePaginatedQuery
convex/react and convex/browser work unchanged: live queries over WebSocket, optimistic updates, pagination, ConvexHttpClient. CORS is open, so localhost works.
5Call functions without a client
curl -s -X POST https://convex.edifear.com/api/query \
-H 'Content-Type: application/json' -d '{"path":"todos:list","args":[{}]}'
curl -s -X POST https://convex.edifear.com/api/mutation \
-H 'Content-Type: application/json' -d '{"path":"todos:add","args":[{"text":"hello"}]}'
Also /api/action. path is module:export (users/profile:get for nested files). Responses are {"status":"success","value":…,"logLines":[…]} or HTTP 560 with {"status":"error","errorMessage":"…","errorData":…}.
6Inspect
These need Authorization: Bearer $CONVEX_ADMIN_KEY (the CLI adds it from the env).
node $CONVEX_LITE tables --url https://convex.edifear.com
node $CONVEX_LITE data todos --url https://convex.edifear.com --limit 20
node $CONVEX_LITE logs --url https://convex.edifear.com --limit 50
node $CONVEX_LITE run todos:list --url https://convex.edifear.com
Raw routes: GET /api/inspect/functions, /api/inspect/tables, /api/inspect/data?table=todos&limit=100, /api/inspect/logs?limit=100.
7What works, what doesn't (v0)
Works
- Schema + indexes (
by_id,by_creation_time,.index()) db.get / insert / patch / replace / deletewithIndexranges (eq, gt, gte, lt, lte),order,filter,take / first / unique / collect,paginate- Nested documents, every Convex value type,
ConvexError - Live subscriptions with per-index-range invalidation
- Actions with
fetch;console.login the function log
Not yet — each returns a clear NotSupported error
- Auth:
ctx.auth.getUserIdentity()always returnsnull ctx.scheduler(runAfter/runAt) and cron jobsctx.storage(file storage)- HTTP actions (
httpRouter) ctx.runQuery/runMutationinside queries and mutations (fine inside actions)- Full-text / vector search, components, Node.js runtime actions
8Limits and error codes
| Per function call | Limit |
|---|---|
| Documents read / bytes read | 16 384 / 8 MiB |
| Writes per mutation | 8 192 |
| Document size / nesting | 1 MiB / 16 levels |
| Time: query, mutation / action | 10 s / 60 s |
| Isolate memory | 64 MiB |
Error codes: ArgumentValidationError, SchemaValidation, FunctionNotFound, FunctionTypeMismatch, IndexNotFound, InvalidIndexRange, RowsReadLimit, BytesReadLimit, WritesLimit, DocumentTooLarge, DocumentNotFound, NotAllowedInQueryOrMutation, FunctionTimeout, NotSupported. Every message says what to change.
9One shared app
default). Everyone who pushes replaces the same function set and shares the same tables. Use unique table names or coordinate before pushing. Per-project apps (<name>.convex.edifear.com) are planned.