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:
- Bun – The JavaScript runtime and package manager used for both frontend and backend scripts. Install from bun.sh.
- Rust – Required for compiling Tauri and native dependencies. Install via
rustup. - 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 setupinstalls dependencies,make docker-upstarts infrastructure. - Configure environment: Copy
.env.exampleto.envin both root andbackend/directories. - Start services: Run backend with
bun devinbackend/, frontend withbun devin root (available athttp://localhost:1420). - Build native apps: Use
bun tauri:dev:desktop,bun tauri:dev:ios, orbun tauri:dev:androidfor cross-platform testing. - Optional features: Enable local LLM providers via
frontend/src/lib/settings.tsand toggle end-to-end encryption viaENABLE_E2E_ENCRYPTIONin.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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →