Skip to content

Installation

CruzJS is a full-stack TypeScript framework built on React Router v7 with tRPC, Drizzle ORM, and Inversify dependency injection. It deploys to Cloudflare Workers/Pages with D1, KV, R2, Queues, and Workers AI. (Multi-cloud is on the roadmap.)

Before you begin, make sure you have:

  • Node.js 20+ — CruzJS uses modern Node.js features
  • npm (or your preferred package manager) — no monorepo or workspace setup required
  • A Cloudflare account (if deploying to Cloudflare) — free tier is sufficient for development and small projects. Other deployment targets have their own prerequisites.

The fastest way to get started is with create-cruz-app:

Terminal window
npx create-cruz-app my-app

This scaffolds a complete CruzJS application with the core framework and UI components pre-configured. The @cruzjs/core, @cruzjs/start, and @cruzjs/saas packages are installed as regular npm dependencies.

Terminal window
# Default: core + start (UI components and theming)
npx create-cruz-app my-app
# Include pro features (organizations, billing, permissions, admin)
# Include billing (Stripe), admin dashboard, and audit logging
npx create-cruz-app my-app --with-pro
# Core only (no UI package, no pro features)
npx create-cruz-app my-app --core-only

After scaffolding, install dependencies and start developing:

Terminal window
cd my-app
npm install
cp .env.example .env
cruz dev

Your package.json will include the CruzJS packages as dependencies:

{
"dependencies": {
"@cruzjs/core": "^1.0.0",
"@cruzjs/start": "^1.0.0",
"react-router": "^7.0.0",
"drizzle-orm": "^0.30.0",
"inversify": "^6.0.0",
"reflect-metadata": "^0.2.0",
"zod": "^3.0.0",
"@trpc/client": "^11.0.0",
"@trpc/react-query": "^11.0.0",
"@trpc/server": "^11.0.0",
"@tanstack/react-query": "^5.0.0"
},
"devDependencies": {
"@cruzjs/cli": "^1.0.0",
"drizzle-kit": "^0.21.0",
"@cloudflare/workers-types": "^4.0.0",
"typescript": "^5.0.0",
"wrangler": "^3.0.0"
}
}

If you have an existing React Router v7 project on Cloudflare Pages, you can add CruzJS packages manually.

Install the core framework:

Terminal window
npm install @cruzjs/core @react-router/cloudflare react-router drizzle-orm inversify reflect-metadata zod @trpc/client @trpc/react-query @trpc/server @tanstack/react-query

Add UI components (optional but recommended):

Terminal window
npm install @cruzjs/start

Add pro features for organizations, billing, and admin (optional):

Terminal window
npm install @cruzjs/saas

Install dev dependencies:

Terminal window
npm install -D @cruzjs/cli drizzle-kit @cloudflare/workers-types typescript wrangler

Create server.cloudflare.ts to bootstrap your application with createCruzApp():

import { createCruzApp } from '@cruzjs/core';
import { CloudflareAdapter } from '@cruzjs/adapter-cloudflare';
import * as schema from './database/schema';
export default createCruzApp({
schema,
modules: [], // Add your feature modules here
adapter: new CloudflareAdapter(),
pages: () => import('virtual:react-router/server-build'),
});

Create src/database/schema.ts to export all database tables:

/**
* Application Database Schema
*/
// Re-export all tables from @cruzjs/start (includes core and pro)
export * from '@cruzjs/start/database/schema';
// Add your app-specific tables below

If you are not using @cruzjs/start, export from the packages you have installed:

export * from '@cruzjs/core/database/schema';
// export * from '@cruzjs/saas/database/schema'; // if using @cruzjs/saas

Your entry.server.tsx handles SSR rendering. The createCruzApp() call in server.cloudflare.ts handles all bootstrap logic — no separate setup import is needed:

import type { AppLoadContext, EntryContext } from 'react-router';
import { ServerRouter } from 'react-router';
import { renderToReadableStream } from 'react-dom/server';
import { CloudflareContext } from '@cruzjs/core/shared/cloudflare/context';
export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
entryContext: EntryContext,
loadContext: AppLoadContext
) {
// Initialize Cloudflare bindings and database from load context
await CloudflareContext.init(loadContext);
const stream = await renderToReadableStream(
<ServerRouter context={entryContext} url={request.url} />
);
responseHeaders.set('Content-Type', 'text/html');
return new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
});
}

Create a .env file in your project root with the required variables:

# Database — local database for development (SQLite for Cloudflare, PostgreSQL for other adapters)
# DATABASE_URL= # Adapter-specific; Cloudflare adapter auto-configures via D1 bindings
# Auth — generate a secure random string (openssl rand -base64 32)
AUTH_SECRET=change-me-in-production
# OAuth (optional — configure for social login)
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Encryption key for sensitive data
SCM_ENCRYPTION_KEY=
# Stripe (only if using @cruzjs/saas billing)
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=

The AUTH_SECRET is used for session encryption and must be a strong random value in production. Generate one with:

Terminal window
openssl rand -base64 32

Start the development server:

Terminal window
cruz dev

This starts a local development server with:

  • Hot module replacement via Vite
  • Local database — SQLite via D1 emulation (Cloudflare adapter) or PostgreSQL (other adapters)
  • In-memory KV namespace for caching
  • Full tRPC endpoint at /api/trpc/*

Visit http://localhost:5173 to see your application.

Generate and apply your initial database migration:

Terminal window
# Generate migration files from your schema
cruz db generate
# Apply migrations to local database
cruz db migrate
# Optional: seed with test data
cruz db seed

Open Drizzle Studio to inspect your database:

Terminal window
cruz db studio

Run the type checker to confirm there are no issues:

Terminal window
cruz typecheck