Skip to content

Installation

CruzJS is a full-stack TypeScript framework built on React Router v7 with tRPC, Drizzle ORM, and Inversify dependency injection. Cloudflare is the default deployment target, but runtime adapters support AWS, GCP, Azure, DigitalOcean, and Docker.

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/pro 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)
# Note: @cruzjs/pro is a premium upgrade that is not yet publicly released.
# The --with-pro flag is for early access preview only.
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/pro

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/pro/database/schema'; // if using @cruzjs/pro

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/pro billing -- premium, not yet released)
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