Skip to content

Contributing to MeshQL

Thank you for your interest in contributing to MeshQL.

Terminal window
git clone https://github.com/meshql/meshql.git
cd meshql
pnpm install
pnpm build
pnpm test

Requirements: Node.js 22+ (CI uses 24), pnpm 11.

  1. Fork the repository and create a branch from main.
  2. Make your changes in the appropriate package under packages/.
  3. Add or update tests in @meshql/core when changing engine behavior.
  4. Run checks before opening a PR:
Terminal window
pnpm build
pnpm test
pnpm check-types
pnpm format
PathPurpose
packages/coreParser, planner, shaper, SQL builder
packages/httpHTTP transport and framework adapters
packages/clientClient SDK
packages/uploadUpload extension
packages/integrityRequest integrity / signing
packages/accessAccess control helpers
examples/Runnable examples
docs/Usage guides

HTTP setup: docs/http-adapters.md.

The intended 1.0 surface is documented in docs/PUBLIC_API.md (application vs adapter vs advanced exports). Rules:

  • New optional exports and options are fine; mark unstable APIs @experimental until they are listed there.
  • Removing, renaming, or requiring new arguments is breaking — add a changeset and a migration note even before 1.0.
  • Do not un-export SQL/ORM helpers from @meshql/core without checking dialect packages; they are public adapter API.
  • Security-relevant behavior belongs in docs/threat-model.md and specs/, not only in code comments.

MeshQL is a pnpm + Turbo monorepo with independent per-package versions. Each library can ship on its own schedule. npm and JSR share the same semver per package (package.json is the source of truth; jsr.json is synced automatically).

Packagenpm nameJSR name
@meshql/core@meshqljs/core@meshql/core
@meshql/postgres@meshqljs/postgres@meshql/postgres
@meshql/sqlite@meshqljs/sqlite@meshql/sqlite
@meshql/http@meshqljs/http@meshql/http
@meshql/client@meshqljs/client@meshql/client
@meshql/upload@meshqljs/upload@meshql/upload
@meshql/integrity@meshqljs/integrity@meshql/integrity
@meshql/access@meshqljs/access@meshql/access
@meshql/prisma@meshqljs/prisma@meshql/prisma
@meshql/drizzle@meshqljs/drizzle@meshql/drizzle
@meshql/kysely@meshqljs/kysely@meshql/kysely
@meshql/persisted-queries@meshqljs/persisted-queries@meshql/persisted-queries
@meshql/access-cache@meshqljs/access-cache@meshql/access-cache
@meshql/pubsub@meshqljs/pubsub@meshql/pubsub
@meshql/sse@meshqljs/sse@meshql/sse
@meshql/codemods@meshqljs/codemods@meshql/codemods
@meshql/gateway@meshqljs/gateway@meshql/gateway
@meshql/docs@meshqljs/docs@meshql/docs

@meshql/typescript-config is private and never published.

Publish order (when multiple packages release together): core → postgres → sqlite → prisma → drizzle → kysely → http → upload → client → integrity → access → persisted-queries → access-cache → pubsub → sse → codemods → gateway → docs.

  1. Add a changeset in your feature PR when you ship user-facing changes:
Terminal window
pnpm changeset

Choose the affected package(s) and semver bump (patch / minor / major). This creates a file under .changeset/.

  1. Merge your PR to main. If changesets are pending, CI opens or updates a Version Packages PR (.github/workflows/release.yml).

    One-time repo setting (required): GitHub → Settings → Actions → General → enable Read and write permissions for workflows, and check Allow GitHub Actions to create and approve pull requests. Without this, the Version Packages PR cannot be opened automatically.

  2. Merge the Version Packages PR. It bumps package.json, syncs jsr.json, and updates per-package CHANGELOG.md files.

  3. CI creates per-package tags on main. Tag push triggers publish.yml:

    • npm: npm/{pkg}/v{version} → publishes @meshqljs/{pkg}
    • JSR: {pkg}/v{version} → publishes @meshql/{pkg}

Example: releasing only @meshql/core at 0.1.4 pushes npm/core/v0.1.4 and core/v0.1.4 — no umbrella tag required.

Bump version in packages/{pkg}/package.json, run node scripts/sync-jsr-versions.mjs, update the package CHANGELOG.md, commit, then:

Terminal window
git tag npm/core/v0.1.4
git tag core/v0.1.4
git push origin npm/core/v0.1.4 core/v0.1.4

Or use Actions → Publish → Run workflow to retry a package (choose registry: npm, jsr, or both) without retagging.

These still work but are not the primary release path:

TagPublishes
npm/all/v* / all/v*core, http, upload, client only
npm/security/v* / security/v*integrity + access together

JSR packages ship TypeScript source (jsr.json exports). CI rewrites workspace:* deps before publish.

One-time JSR setup (required for each package)

Section titled “One-time JSR setup (required for each package)”

JSR OIDC only works for packages linked to your GitHub repo. Creating @meshql/core is not enough.

For each publishable package:

  1. Go to jsr.io/new and create it under the @meshql scope (if not created yet).
  2. Open the package on JSR → Settings → GitHub repository.
  3. Enter meshql/meshql and click Link.
  4. Ensure packages/{pkg}/README.md exists (publish verify fails without it).

Setup checklist:

PackageJSR createdGitHub linked
@meshql/coreyesyes
@meshql/httpyesyes
@meshql/clientyesyes
@meshql/uploadyesyes
@meshql/integrityyesyes
@meshql/accessyesyes
@meshql/persisted-queriesyesyes
@meshql/access-cacheyesyes

Without linking, CI fails with actorNotAuthorized or Following packages don't exist. See docs/jsr-settings.md for descriptions and runtime compatibility.

Tag-push publishes use GitHub OIDC (id-token: write) — no dispatch workaround. Keep RELEASE_PAT for the Changesets version PR only.

Terminal window
pnpm build
pnpm publish:dry-run # npm pack + jsr --dry-run for all packages
pnpm publish:local -- --registry jsr --package core --dry-run
pnpm publish:jsr # all publishable packages, in workspace order

Already-published versions are skipped automatically by jsr publish.

Packages publish under the @meshqljs npm org as compiled ESM (dist/). Workspace and JSR names stay @meshql/*.

RegistryNameExample
npm@meshqljs/<pkg>npm i @meshqljs/core
JSR@meshql/<pkg>npx jsr add @meshql/core
  1. Create an npm access token with Automation or Publish scope (member of @meshqljs).
  2. Add it to the GitHub repo:
Terminal window
gh secret set NPM_TOKEN --repo meshql/meshql
  1. First publish of each package claims @meshqljs/<pkg> on npm.
TriggerExamplePublishes
Per-package tagnpm/core/v0.1.3@meshqljs/core only
Per-package tagnpm/http/v0.1.3@meshqljs/http only
Umbrella tagnpm/all/v0.1.3core → … → client (see tag list)
Manual dispatchActions → Publishselected package(s) / registry

Each npm tag push creates a GitHub Release with .tgz assets.

Terminal window
pnpm build
pnpm publish:dry-run
pnpm publish:npm:pack # writes artifacts/*.tgz for all publishable packages

scripts/prepare-npm-publish.mjs rewrites package.json for publish (@meshqljs/* names, workspace:* → semver, strip devDeps) and rewrites @meshql/* imports in dist/ to @meshqljs/*. Workspace pnpm build keeps @meshql/* so tests resolve. CI restores manifests and dist after each package.

  • Keep PRs focused - one feature or fix per PR when possible.
  • Add a changeset (pnpm changeset) for user-facing package changes; CI opens a Version Packages PR.
  • For small doc-only changes with no release, a changeset is optional.
  • Changing a frozen export in docs/PUBLIC_API.md needs an explicit mention in the PR.
  • Write clear commit messages and PR descriptions explaining why, not just what.
  • Ensure CI passes.
  • Bugs: include reproduction steps, expected vs actual behavior, and environment (Node version, OS).
  • Features: describe the use case and how it fits MeshQL’s scope (REST + shaped queries, minimal ceremony).
  • TypeScript strict mode; match existing patterns in the package you’re editing.
  • Prefer small, focused changes over large refactors unless discussed first.
  • Comments only where behavior is non-obvious.

By contributing, you agree that your contributions will be licensed under the MIT License.