Skip to main content
This guide will walk you through setting up Hazel Chat locally and sending your first message.

Prerequisites

Before you begin, make sure you have:
Hazel requires Bun v1.2.14+ for workspace catalogs, a feature that centralizes Effect-TS dependencies across the monorepo.

Setup in 4 steps

1

Clone and install

Clone the repository and install dependencies:
git clone <repository-url>
cd hazel-chat
bun install
This installs all dependencies across the monorepo using Bun’s workspace feature.
2

Run the setup wizard

The interactive setup wizard handles all configuration:
bun run setup
The wizard will:
  • Start Docker services (PostgreSQL, Redis, Electric SQL, MinIO)
  • Validate your environment
  • Configure WorkOS authentication
  • Generate secure secrets
  • Create .env files for all apps
  • Initialize the database schema
You’ll need your WorkOS credentials during setup. Have your Client ID, API Key, and Redirect URI ready from the WorkOS dashboard.
3

Configure WorkOS

While the setup wizard creates your .env files, you need to configure a few things in WorkOS:

Enable AuthKit

  1. Go to AuthenticationAuthKit in your WorkOS dashboard
  2. Click “Get started” or “Enable AuthKit”
  3. Configure your app name and branding
  4. Enable at least one sign-in method (Email + Password, Google, GitHub, etc.)

Set redirect URI

Add this redirect URI in RedirectsEdit redirect URIs:
http://localhost:3003/auth/callback

Create roles

Go to Roles and create these three roles:
Role SlugNameDescription
ownerOwnerFull access, can delete organization
adminAdminCan manage members and settings
memberMemberStandard access (default)
Without these roles, organization member management will fail. Make sure to create all three exactly as specified.
4

Start the development server

Launch all services with Turborepo:
bun run dev
This starts:
The first build may take 30-60 seconds. Subsequent starts are much faster thanks to Vite’s caching.

Your first message

Now that everything is running, let’s send your first message:
1

Create an account

  1. Open http://localhost:3000 in your browser
  2. Click “Sign up” or “Get started”
  3. Complete the WorkOS authentication flow
  4. You’ll be redirected to create your first organization
2

Create an organization

  1. Enter your organization name (e.g., “Acme Corp”)
  2. Choose a unique slug (e.g., “acme”)
  3. Click “Create organization”
You’ll be taken to your organization’s default #general channel.
3

Send a message

  1. Click in the message input at the bottom
  2. Type your message: “Hello, Hazel!”
  3. Press Enter or click the send button
Your message appears instantly thanks to Electric SQL’s local-first sync.
4

Explore features

Try these features:
  • Create a channel: Click the + next to “Channels” in the sidebar
  • React to messages: Hover over a message and click the emoji button
  • Pin a message: Hover over a message, click the ··· menu, and select “Pin”
  • Upload a file: Click the paperclip icon in the message input
  • Invite team members: Go to Settings → Members → Invite

What just happened?

When you sent that message, here’s what happened behind the scenes:
  1. Client-side: The message was optimistically added to your local TanStack DB store
  2. RPC call: An Effect RPC request was sent to the backend’s message.create handler
  3. Backend: The message was validated, rate-limited, and inserted into PostgreSQL
  4. Real-time sync: Electric SQL detected the database change and synced it to all connected clients
  5. Workflow: Effect Cluster triggered a MessageNotificationWorkflow to notify channel members
All of this happened in milliseconds with full type safety.

Development workflow

Now that you’re set up, here’s the typical development workflow:

File structure

The monorepo is organized by concern:
apps/
├── web/                 # Frontend - React components, routes, UI
├── backend/             # Backend - RPC handlers, services, policies
├── cluster/             # Cluster - Workflows and distributed entities
packages/
├── domain/              # Shared - RPC contracts, types, models
├── db/                  # Shared - Database schema and migrations
└── backend-core/        # Shared - Reusable backend services

Common tasks

bun run typecheck

Making changes

Adding a new RPC endpoint:
  1. Define the contract in packages/domain/src/rpc/
  2. Implement the handler in apps/backend/src/rpc/handlers/
  3. Call it from the frontend using the generated RPC client
Adding a database table:
  1. Add the schema in packages/db/src/schema/
  2. Generate a migration: bun run db:generate
  3. Push to the database: bun run db:push
  4. Update the Electric proxy allowlist in apps/electric-proxy/src/tables/user-tables.ts
Creating a workflow:
  1. Define it in packages/domain/src/cluster/workflows/
  2. Implement it in apps/cluster/src/workflows/
  3. Trigger it from the backend using WorkflowClient
See the Architecture guide for detailed patterns and the API Reference for all available endpoints.

Next steps

Architecture

Understand the system design and patterns

API Reference

Explore all RPC and HTTP endpoints

Effect-TS Guide

Learn Effect-TS patterns used throughout the codebase

Deployment

Deploy to production

Troubleshooting

Make sure Docker Desktop is running and you have sufficient permissions:
docker ps  # Should list running containers
If Docker isn’t running, start Docker Desktop and try again.
Hazel requires Bun v1.2.14 or later for workspace catalogs:
bun --version  # Should be 1.2.14 or higher
Update Bun: curl -fsSL https://bun.sh/install | bash
If you see “Port 3000 is already in use”, another application is using that port.Find and kill the process:
# On macOS/Linux
lsof -ti:3000 | xargs kill -9

# On Windows
netstat -ano | findstr :3000
taskkill /PID <PID> /F
Double-check your WorkOS configuration:
  1. Verify the redirect URI is exactly http://localhost:3003/auth/callback
  2. Confirm AuthKit is enabled with at least one sign-in method
  3. Check that your .env files have the correct WorkOS credentials
  4. Ensure the three roles (owner, admin, member) are created
Electric SQL requires PostgreSQL with logical replication:
# Check if Electric is running
curl http://localhost:3333/v1/health
If you get a connection error, restart the Docker services:
docker-compose down
docker-compose up -d

Get help

If you’re stuck:

Build docs developers (and LLMs) love