Run MeshQL in 5 minutes
Get a working MeshQL stack — reads, signed auth, list queries, and uploads — with no Docker.
MeshQL is published on JSR (@meshql/*) and npm (meshql-*). Current release line: 0.7.x.
Fastest path — interactive showcase
Section titled “Fastest path — interactive showcase”Full-stack blog demo (React + @meshql/client on SQLite):
git clone https://github.com/meshql/meshql.gitcd meshqlpnpm install && pnpm buildpnpm --filter showcase startOpen http://localhost:3010/ — sign in with ada@example.com / demo and watch DevTools → Network for /mesh/* calls.
Optional CLI tour of the same API:
pnpm --filter showcase demoSee examples/showcase/README.md.
Step 1 — Create a project
Section titled “Step 1 — Create a project”Node (npm)
Section titled “Node (npm)”mkdir my-meshql-app && cd my-meshql-appnpm init -ynpm pkg set type=modulenpm i -D typescript tsx @types/nodenpx tsc --init --module nodenext --moduleResolution nodenext --target ES2022 --outDir dist --rootDir srcmkdir srcmkdir my-meshql-app && cd my-meshql-appbun init -ymkdir srcStep 2 — Install MeshQL
Section titled “Step 2 — Install MeshQL”JSR:
npx jsr add @meshql/core @meshql/sqlite @meshql/http @meshql/client @meshql/integritynpm:
npm install meshql-core meshql-sqlite meshql-http meshql-client meshql-integrityAdd Express:
npm i expressnpm i -D @types/express # Node onlyStep 3 — Minimal SQLite server
Section titled “Step 3 — Minimal SQLite server”Uses Node 22.5+ built-in node:sqlite — no native deps.
import { DatabaseSync } from "node:sqlite";import { createMesh, type MeshSchema } from "@meshql/core";import { buildSelectSql } from "@meshql/sqlite";import { meshIntegrityExpressRouter } from "@meshql/integrity/express";import { withIntegrity } from "@meshql/integrity";import express from "express";
const schema: MeshSchema = { entities: { user: { fields: ["id", "name", "email"], table: "users" }, }, joins: {},};
const db = new DatabaseSync(":memory:");db.exec(` CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT); INSERT INTO users VALUES (1, 'Ada Lovelace', 'ada@example.com');`);
const base = createMesh(schema);const mesh = withIntegrity(base, { secret: process.env.MESH_SECRET ?? "dev-secret", authenticate: async (creds) => { const { email } = creds as { email?: string }; const row = db.prepare("SELECT id FROM users WHERE email = ?").get(email ?? "") as | { id: number } | undefined; if (!row) throw new Error("Invalid credentials"); return { userId: String(row.id), sessionId: crypto.randomUUID(), role: "user" }; },});
mesh.resolve("*", async (plan) => { const { sql, params } = buildSelectSql(plan, schema); return db.prepare(sql).all(...params);});
const app = express();app.use(express.json());app.use(meshIntegrityExpressRouter(mesh, mesh.integrity, "/mesh"));
app.listen(3001, () => { console.log("MeshQL on http://localhost:3001/mesh");});Run:
npx tsx src/index.tsStep 4 — Test with the client SDK
Section titled “Step 4 — Test with the client SDK”import { createAuthClient } from "@meshql/client";
const client = createAuthClient({ url: "http://localhost:3001/mesh", format: "json" });
await client.login({ email: "ada@example.com" });
// Point readconst user = await client.query( { user: { $select: { id: true, name: true, email: true } } }, { entityId: "1" },);console.log("user:", user);
// Collection readconst users = await client.query( { user: { $select: { id: true, name: true }, $page: { first: 10 }, $orderBy: [{ field: "id", direction: "asc" }], }, },);console.log("list:", users.items, users.pageInfo);npx tsx src/client-demo.tsSee client.md for browser usage, uploads, and React integration.
Step 5 — Test with curl
Section titled “Step 5 — Test with curl”Login (integrity)
Section titled “Login (integrity)”curl -s -X POST http://localhost:3001/mesh/auth \ -H "Content-Type: application/json" \ -d '{"email":"ada@example.com"}'Save signingToken and token from the response for signed queries.
Signed GET (manual)
Section titled “Signed GET (manual)”Base64-encode the query JSON:
mesh_query() { echo -n "$1" | base64 | tr -d '\n'}
Q=$(mesh_query '{"user":{"$select":{"id":true,"name":true}}}')
# Sign with your signingToken (see @meshql/http signQuery or use the client)curl -s "http://localhost:3001/mesh/user/1" \ -H "X-Mesh-Query: $Q" \ -H "X-Mesh-Format: json" \ -H "X-Mesh-Token: $TOKEN" \ -H "X-Mesh-Signature: sha256=..."Prefer @meshql/client — it handles encoding and signing automatically.
Collection with read controls
Section titled “Collection with read controls”Q=$(mesh_query '{"user":{"$select":{"id":true,"name":true},"$page":{"first":10}}}')
curl -s "http://localhost:3001/mesh/user" \ -H "X-Mesh-Query: $Q" \ -H "X-Mesh-Format: json" \ -H "X-Mesh-Token: $TOKEN" \ -H "X-Mesh-Signature: sha256=..."Read controls live in the signed payload, not URL query strings.
Missing header (expected error)
Section titled “Missing header (expected error)”curl -s "http://localhost:3001/mesh/user/1"{ "error": "TransportError", "message": "Missing X-Mesh-Query header"}Other examples
Section titled “Other examples”| Example | Stack | Highlights |
|---|---|---|
| showcase | React + SQLite + integrity + access + uploads | Full dashboard, browser client |
| express-sqlite | Express + SQLite | Minimal SQL adapter |
| express-postgres | Express + Postgres + uploads | Avatar upload demo |
Related
Section titled “Related”- HTTP adapters — routes, headers, uploads, errors
- Client SDK — browser, auth, list queries, uploads
- README — project overview