How to Set Up a Local Development Environment for Thunderbolt: A Complete Guide

To set up a local development environment for Thunderbolt, install Bun, Rust, and Docker, then run make setup, configure your .env files, start the Docker infrastructure with make docker-up, and launch the backend (bun dev in backend/) and frontend (bun dev in root) in separate terminals.

Thunderbolt is a cross-platform AI client built by the Thunderbird team that combines a React + Vite frontend, a Bun‑powered Elysia backend, and Tauri for desktop and mobile builds. This guide walks you through the exact commands and file configurations needed to build and run the entire stack on your local machine, based on the official repository structure in thunderbird/thunderbolt.

Prerequisites for Thunderbolt Development

Before cloning the repository, ensure you have the three core toolchains installed:

  1. Bun – The JavaScript runtime and package manager used for both frontend and backend scripts. Install from bun.sh.
  2. Rust – Required for compiling Tauri and native dependencies. Install via rustup.
  3. Docker – Used to orchestrate PostgreSQL, PowerSync, and optional services. Docker Desktop or the Docker engine is sufficient.

Step-by-Step Setup Guide

Install Node-Level Dependencies

The repository provides a make setup target that runs bun install for both the frontend and the backend, and also pulls in any required Rust crates for Tauri.

git clone https://github.com/thunderbird/thunderbolt.git
cd thunderbolt
make setup

Configure Environment Files

The repo ships example .env files that contain the necessary configuration variables for the backend and the client. Copy them to .env in the project root and in backend/:

cp .env.example .env
cp backend/.env.example backend/.env

Start the Infrastructure Stack

Run make docker-up to spin up a PostgreSQL database and a PowerSync server via Docker Compose:

make docker-up

Run the Backend

Start the API server with bun dev inside the backend/ folder. This launches the Elysia application defined in backend/src/main.ts.

cd backend
bun dev

Run the Frontend

From the project root, execute bun dev; the Vite dev server will be reachable at http://localhost:1420. This mounts the React entry point in src/index.tsx.

bun dev

Run the Native App

Tauri can be launched for different platforms using the provided npm scripts:

  • Desktop: bun tauri:dev:desktop
  • iOS Simulator: bun tauri:dev:ios
  • Android Emulator: bun tauri:dev:android

These steps are documented in the official development guide at docs/development.md (lines 5‑34).

Architecture Overview

Understanding the three-zone architecture helps you navigate the codebase when debugging or extending features:

Zone Components Role
User Device UI (React 19 + Radix), State (Zustand + TanStack Query + Drizzle), AI client (Vercel AI SDK + MCP), optional E2E encryption, SQLite Runs the entire UI, local data store, and optional client‑side encryption.
Server Infrastructure Backend API (Elysia on Bun), Auth (Better Auth + OTP + OIDC), Inference Proxy (rate‑limiting & routing), PowerSync (sync engine), PostgreSQL Provides authentication, model routing, and the sync back‑end that stores encrypted payloads.
External Services LLM providers (Anthropic, OpenAI, Mistral, OpenRouter), OAuth providers (Google, Microsoft), PostHog (analytics), Resend (email) Third‑party SaaS that the server talks to.

Key architectural properties include:

  • Offline‑first – SQLite is the source of truth; the app works without a network connection.
  • Cross‑platform – a single React codebase compiles to desktop (macOS, Linux, Windows) and mobile (iOS, Android) via Tauri.
  • Model‑agnostic – the inference proxy abstracts away LLM providers, allowing you to plug in any OpenAI‑compatible API key or a local model server (e.g., Ollama).
  • Self‑hostable – the whole stack (backend, DB, PowerSync, auth) can be run locally with Docker Compose, making it ready for on‑prem deployments.

Key Development Files

File Description Link
docs/development.md Full quick‑start guide, required tools, make commands development.md
docs/architecture.md Mermaid diagram, zone breakdown, architectural properties architecture.md
backend/src/main.ts Entry point for the Bun + Elysia API server main.ts
src/index.tsx React entry point, mounts the UI, sets up Zustand store index.tsx
src/lib/http.ts Centralised HTTP client used by both frontend and backend http.ts
deploy/README.md Docker‑Compose and Kubernetes deployment instructions deploy/README.md
scripts/tauri.ts Tauri build scripts for desktop, iOS, Android tauri.ts
src/lib/crypto.ts Optional end‑to‑end encryption helpers crypto.ts

These files together form the core of the local development workflow: the docs guide you through setup, the backend/src/main.ts and src/index.tsx launch the server and UI, and the auxiliary libraries (http.ts, crypto.ts) illustrate how the frontend talks to the backend and optionally encrypts data.

Common Configuration Examples

One-Liner to Bootstrap the Repository

Clone, install dependencies, and prepare environment files in a single sequence:


# Clone, install, and start everything

git clone https://github.com/thunderbird/thunderbolt.git && cd thunderbolt
make setup && cp .env.example .env && cp backend/.env.example backend/.env
make docker-up        # PostgreSQL + PowerSync

# In separate terminals:

(cd backend && bun dev)   # backend API

bun dev                   # Vite dev server (http://localhost:1420)

Running the Desktop Client

Launch the Tauri desktop wrapper after the frontend dev server is running:

bun tauri:dev:desktop   # opens the Tauri window on macOS / Linux / Windows

Adding a Local LLM Provider (Ollama)

To integrate a local Ollama instance, create a model entry in frontend/src/lib/settings.ts:

export const MODEL_PROVIDERS = [
  {
    id: "ollama",
    name: "Ollama",
    endpoint: "http://localhost:11434/v1",
    apiKey: "",               // not required for local Ollama
  },
];

The UI will then list “Ollama” as a selectable model in the Settings screen.

Enabling Optional End-to-End Encryption

Set the environment variable in .env:

ENABLE_E2E_ENCRYPTION=true

When the app starts, the encryption layer (src/lib/crypto.ts) will wrap all outgoing sync payloads with the client‑side key before sending them to PowerSync.

Summary

  • Install three toolchains: Bun (JavaScript runtime), Rust (for Tauri), and Docker (for PostgreSQL/PowerSync).
  • Use Make targets: make setup installs dependencies, make docker-up starts infrastructure.
  • Configure environment: Copy .env.example to .env in both root and backend/ directories.
  • Start services: Run backend with bun dev in backend/, frontend with bun dev in root (available at http://localhost:1420).
  • Build native apps: Use bun tauri:dev:desktop, bun tauri:dev:ios, or bun tauri:dev:android for cross-platform testing.
  • Optional features: Enable local LLM providers via frontend/src/lib/settings.ts and toggle end-to-end encryption via ENABLE_E2E_ENCRYPTION in .env.

Frequently Asked Questions

What are the minimum hardware requirements for running Thunderbolt locally?

Thunderbolt runs efficiently on standard development hardware. You need approximately 4 GB of RAM to run the Docker stack (PostgreSQL and PowerSync) alongside the Bun backend and Vite frontend. For mobile development using the iOS Simulator or Android Emulator, macOS or a Linux distribution with KVM support is required, plus at least 10 GB of free disk space for Rust toolchains and Tauri build artifacts.

Can I use a local LLM like Ollama instead of cloud providers?

Yes, Thunderbolt supports model-agnostic inference through its configuration layer. Add your local Ollama endpoint to the MODEL_PROVIDERS array in frontend/src/lib/settings.ts with the endpoint http://localhost:11434/v1 and an empty API key. The UI will automatically display Ollama as a selectable provider in the Settings screen, routing all chat completions through your local instance.

How do I enable end-to-end encryption for local development?

Set the environment variable ENABLE_E2E_ENCRYPTION=true in your root .env file before starting the application. When enabled, the encryption layer defined in src/lib/crypto.ts automatically wraps all outgoing sync payloads with client-side keys before transmitting them to the PowerSync server. This ensures that even if the local PostgreSQL database is compromised, the data remains encrypted and unreadable without the client's decryption key.

Is it possible to develop without Docker for the database layer?

While the official workflow recommends Docker for running PostgreSQL and PowerSync via make docker-up, you can manually install PostgreSQL 15+ and run the PowerSync service as a standalone binary if you prefer a container-free environment. However, you must ensure the database connection strings in backend/.env match your manual setup, and you will lose the convenience of the pre-configured Docker Compose network that handles service discovery between the sync engine and the backend API.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →