Warlock.js
The full-stack TypeScript framework for server-rendered React, typed HTTP and data, and production-ready AI agents — in one application.
Documentation · Getting started · Packages · Contributing · Changelog
Why Warlock.js
Most Node.js stacks make you assemble a server, an ORM, a validator, a queue, an SSR layer and an AI SDK yourself — and then keep them in step forever. Warlock.js ships them as one family of packages, released together at one version, designed to share a lifecycle, a configuration model and a type system.
- One application, every surface. Server-rendered React pages, a typed HTTP API and AI agents live in the same codebase and boot in the same lifecycle.
- Typed end to end. Models, request schemas, resources, page loaders and agent tools are all TypeScript-first, and the whole family typechecks under
strictwithnoUncheckedIndexedAccess. - Batteries included, never forced. Heavy integrations (S3, SES, sharp, socket.io, provider SDKs) are optional peer dependencies — install one only when you use the feature that needs it.
- Lockstep releases. Every package is published at the same version after the whole family passes its typecheck, its tests, a local-registry install and an end-to-end application check.
- AI that is part of the app. Provider-agnostic agents, tools, teams, workflows, RAG, memory and guardrails, with adapters for every major model provider.
Getting started
Create a new application with the scaffolder:
npx create-warlock@latest my-app
cd my-app
npm run dev
The wizard asks what you are building (full-stack web or API only), which database driver to use and which optional features to include — SSR pages, authorization, mail, storage, queues, notifications, AI providers and more — then generates a typed, ready-to-run project. Read the getting-started guide for a full walkthrough.
A taste
// src/app/products/routes.ts — an HTTP API
import { router } from "@warlock.js/core";
import { createProduct, listProducts, showProduct } from "./controllers";
router.get("/api/products", listProducts);
router.post("/api/products", createProduct);
router.get("/api/products/:id", showProduct);
// src/web/products/index.page.tsx — a server-rendered React page
import type { PageLoader, PageProps } from "@warlock.js/web";
import { catalog } from "app/products/catalog";
import ProductGrid from "./product-grid";
export const loader = (async () => ({
products: await catalog.list(),
})) satisfies PageLoader;
export default function Products({ data }: PageProps<typeof loader>) {
return <ProductGrid items={data.products} />;
}
// src/app/support/agents/triage.ts — an AI agent
import { ai } from "@warlock.js/ai";
import { openai } from "./providers";
export const supportAgent = ai.agent({
model: openai.model({ name: "gpt-4o-mini" }),
systemPrompt: "Help customers choose a product.",
});
Packages
All packages live in packages/ and are published to npm at the same version.
Foundation
Application services
AI
Model providers: ai-openai · ai-anthropic · ai-google · ai-bedrock · ai-mistral · ai-groq · ai-deepseek · ai-xai · ai-ollama
Repository layout
framework/
├── packages/ every published package, one directory each
│ ├── core/
│ ├── web/
│ ├── cascade/
│ └── …
├── docs/ the documentation site (Astro + Starlight) → warlock.js.org
├── tools/release/ the release runner: gate, publish and confirm the family
├── scripts/ workspace-wide checks (spec coverage, CI package selection)
├── skills/ agent playbooks for working in this repository
└── .github/workflows/ CI, docs deployment, create-warlock and release pipelines
Each package keeps its own README.md, CHANGELOG.md, tests and agent skills. The full history of every package was carried over from its original repository, so git log and git blame work across the move.
Development
Requirements: Node.js 22.15 or newer (CI uses Node 24) and pnpm 11.24.0. With Corepack enabled, the right pnpm is picked up from packageManager automatically:
corepack enable
git clone https://github.com/warlockjs/framework.git
cd framework
pnpm install
Packages resolve each other from this repository, never from npm, so a change in core is immediately visible to auth, web and every other dependent.
Common tasks
Some suites need services: queue and notifications expect Redis on port 6390, and parts of cascade and auth start databases through Testcontainers, which needs Docker.
docker run -d --name warlock-redis -p 6390:6379 redis:7
Continuous integration
The shared Oxlint check fails on correctness errors; warnings remain advisory.
Unused locals and unsafe optional access stay errors. Override parameters,
intentionally ignored catches, object-rest omissions, snapshot spreads, numeric
array allocation and typed createElement children follow the repository's
existing conventions. Exceptions to safety checks belong on the specific line
with a reason; do not disable a safety rule to conceal a failing check.
Releasing
The family is released in lockstep from GitHub Actions, never from a developer machine. Every package shares one version, so a release starts by moving all of them at once:
pnpm release:version 5.30.0 # every package, the exact family pins and the lockfile
Date each package's ## 5.30.0 CHANGELOG heading, commit, push, then dispatch the release workflow with that version:
- Gate — strictness, every package's typecheck and tests, build, pack, and an install of the tarballs from a local registry.
- Application check — a real application is built and exercised on the release tarballs.
- Publish — only with
publish: true, and only after the gate passes. - Confirm — the published versions are installed back from npm and checked, then
v<version>is tagged.
See tools/release for the details.
Contributing
Contributions are welcome. Before opening a pull request:
- Branch from
mainand keep the change focused on one concern. - Add or update tests next to the code you changed; a fix starts with a failing test.
- Update the package's docs and its
CHANGELOG.mdin the same change. - Run
pnpm --filter <package> typecheckandpnpm --filter <package> testfor each package you touched.
CI must pass before a change is merged. Report security issues privately to the maintainers rather than in a public issue.
License
MIT © Hassan Zohdy
Repository formatting uses the pinned Oxfmt tool and one root .oxfmtrc.json:
run pnpm format to write changes and pnpm format:check to check them. CI checks
the same configuration. Generated references, locks, build output and archived
material are excluded; regenerate their source projections instead. Scaffolder
source uses this root formatter even in its standalone test job. Generated app
templates retain their own toolchain checks.
Oxlint/Oxfmt are the only supported lint and format tools in 5.34.0.
Repository import sorting stays disabled; generated apps use Oxfmt's built-in
import sorting. Migrate legacy apps with npx warlock upgrade --from 5.33 --to 5.34.0.