Vura is the OSS distribution of the ThenJS full-stack framework: file-based API routes, static/server pages, and deployment adapters for Node, AWS Lambda, and Cloudflare Workers.
pnpm add @celsian/then-core @celsian/then-cliThe CLI exposes vura and thenjs as safe command names. The legacy then bin is still shipped for compatibility, but new npm scripts should use vura or thenjs because then is a shell reserved word.
- Node.js 20 or 22 (
engines.nodeis constrained to>=20 <23) - pnpm 10.11.0 (the version pinned by
packageManager)
Recommended activation on fresh machines:
corepack enable
corepack prepare pnpm@10.11.0 --activate
pnpm install --frozen-lockfilepnpm create then@latest my-app
cd my-app
pnpm dev
pnpm buildcreate-then treats dependency installation as part of a successful scaffold. If install fails, the command exits non-zero after writing the files so registry or namespace-access problems cannot be missed. Pass --no-install explicitly to inspect or test the starter shape without installing:
npx create-then my-app --no-installExample scripts:
{
"scripts": {
"dev": "vura dev",
"build": "vura build"
}
}vura deploy is reserved for the managed Vura Platform and intentionally
fails closed in the open-source CLI. Use vura build plus the adapter output
for self-hosted deployments until managed deployment access is available.
The default build emits a standalone Node server at dist/server/entry.js and static assets under dist/static.
pnpm install --frozen-lockfile
pnpm build
PORT=3000 NODE_ENV=production node dist/server/entry.jsSet runtime environment variables in your host dashboard, then health-check your deployed URL. The generated server serves API routes, server/hybrid pages, and static/client pages from one process.
Use the Cloudflare adapter when you want Worker artifacts instead of the Node server:
pnpm add @celsian/then-adapter-cloudflare
# configure then.config.js with the adapter
pnpm build
wrangler deployCloudflare route handlers intentionally receive the same conservative req/reply shim as other generated targets, plus Cloudflare-only escape hatches on req.__cf_env and req.__cf_ctx. Keep this runtime surface narrow until a concrete adapter use case needs a first-class API; widening the shim would become public API surface that must work across Worker, Node, and managed Vura Platform deployments.
Use the Lambda adapter for API Gateway/Lambda packaging:
pnpm add @celsian/then-adapter-lambda
# configure then.config.js with the adapter
pnpm build
sam deploy --guidedvura build now emits deployable build-time output for every non-server page mode:
staticpages prerender todist/static/<route>/index.htmlwith no framework JavaScript added.clientpages prerender a loading shell and emit a browser module underdist/static/_then/pages/*.js; the HTML references that module.hybridpages prerender HTML and emit a matching browser module underdist/static/_then/pages/*.jsfor hydration/island code.serverpages remain runtime-rendered bydist/server/entry.js.
The generated hot server serves API routes first, server/hybrid runtime pages next, and dist/static as the final fallback so static/client assets remain deployable without shadowing APIs.
@celsian/then-core— manifest scanning, build pipeline, generated production server, and runtime helpers.@celsian/then-cli—vura,thenjs, and legacythencommand-line interface.@celsian/then-adapter-lambda— AWS Lambda/API Gateway deployment artifacts.@celsian/then-adapter-cloudflare— Cloudflare Workers deployment artifacts.@celsian/then-vite-plugin— Vite integration.@celsian/then-compiler— pure JavaScript compiler fallback.
Before publishing, run:
corepack enable
corepack prepare pnpm@10.11.0 --activate
pnpm install --frozen-lockfile
pnpm release:checkTo bypass a mismatched local Corepack/global pnpm toolchain, run the same gate with Node 22 and the pinned pnpm directly:
npx -p node@22 -p pnpm@10.11.0 pnpm install --frozen-lockfile
npx -p node@22 -p pnpm@10.11.0 pnpm release:checkpnpm release:check runs the full local gate: private-package assertions, hygiene lint, build, tests, production audit, packed publish smoke, tracked tarball-size limits, npm publish dry-run, whitespace checks, and a clean git tree assertion.
Do not publish from an unverified or dirty release tree. Manual release means running pnpm release:check locally first, then using the tag/manual GitHub release workflow or node scripts/publish-packages.mjs only after npm namespace authority is resolved. If npm returns E403, E404, or any permission/scope uncertainty for @celsian/*, stop: either obtain/admin the @celsian scope or intentionally rename the packages, then rerun the full release check before any real publish. Real publishing always runs a namespace-authority preflight for scoped packages before uploading tarballs; it cannot be bypassed with VURA_SKIP_NPM_SCOPE_PREFLIGHT.