TurboPanel Docs
Getting Started

Local development

This guide covers contributor local development. For host tooling, see Prerequisites. For layout and service dependencies, see Development architecture. For common failures, see Dev console troubleshooting.

TurboPanel is not a monorepo. Clone (or fork) six sibling repositories under one parent directory, then run the stack inside a Vagrant guest. Edit on the host with VS Code / Cursor; Node, Deno, Docker, and systemd run in the VM.

System requirements

We recommend at least an Intel Core i7-4790K (or equivalent) with 16 GB of RAM. Some workloads need more memory, so 24 GB+ is recommended, and 32 GB is ideal.

RequirementRecommendation
CPUIntel Core i7-4790K or equivalent
RAM16 GB minimum · 24 GB+ recommended · 32 GB ideal
SoftwareVagrant plus a provider (libvirt on Linux, UTM on macOS)

Install Vagrant and the provider before vagrant up. Full host tooling, Git/SSH, and provider install notes are on Prerequisites. Additional Vagrant providers for macOS and Linux are welcome — open a PR against TurboPanel/dev.

Repository layout

Use your own forks and feature branches so you can open PRs against trunk:

PLAINTEXT
turbopanel/
├── dev/          # Vagrantfile + Ink console — https://github.com/TurboPanel/dev
├── turbopaneld/  # host daemon + Ansible — https://github.com/TurboPanel/turbopaneld
├── turbopanel/   # control plane — https://github.com/TurboPanel/turbopanel
├── ui/           # Expo product console — https://github.com/TurboPanel/ui
├── website/      # marketing + docs — https://github.com/TurboPanel/website
└── .github/      # community health — https://github.com/TurboPanel/.github

Inside the guest these mount at ~/dev, ~/turbopaneld, ~/turbopanel, ~/ui, ~/website, and ~/.github.

Quick start

1. Install Vagrant and a provider (see Prerequisites).

2. Boot the guest from the dev checkout:

Terminal
cd path/to/turbopanel/dev
vagrant up
vagrant ssh

Plain vagrant up selects libvirt on Linux and UTM on macOS. First boot downloads the box and may reboot once when a newer kernel is pending.

3. Start the console inside the guest:

Terminal
dev/console

That ensures pinned Node, runs pnpm install, and launches the Ink developer console. On a fresh guest the console bootstraps the daemon and converges the stack (optional-services picker after bootstrap). On later launches it sits idle until Developer → Converge / re-converge.

4. Open the control plane from the host

ServiceURL
App (Caddy → UI + API, HTTPS)https://localhost:8443
App (Caddy → UI + API, plaintext)http://localhost:8880
API health (HTTPS)https://localhost:8443/api/health
API health (plaintext)http://localhost:8880/api/health
Website (docs + API reference)http://localhost:19820 (when enabled)
Mailpithttp://localhost:8025 (when enabled; host loopback only)

Trust the platform CA bundle at /var/lib/turbopanel/tls/ca-bundle.pem (after converge, or fetch it from GET /api/daemon/v1/instance/ca) in your browser to avoid TLS warnings on :8443.

Smoke test from the host:

Terminal
curl -k https://localhost:8443/api/health
curl http://localhost:8880/api/health

Ports forwarded to the host

Vagrant forwards these guest ports. Use them from the IDE, browsers, or remote test machines.

PortServiceHost bind
80Hosting Caddy HTTP (tenant sites)0.0.0.0 (LAN)
443Hosting Caddy HTTPS (tenant sites)0.0.0.0 (LAN)
8443Control plane (Caddy HTTPS)0.0.0.0 (LAN)
8880Control plane (Caddy plaintext HTTP)0.0.0.0 (LAN)
8081Expo / Metro (native + direct; Caddy also proxies this)0.0.0.0 (LAN)
8088Optional extra forward (guest must listen)0.0.0.0 (LAN)
19820Website (Next.js)0.0.0.0 (LAN)
4983Drizzle Studio (unauthenticated)127.0.0.1 only
8025Mailpit web UI (unauthenticated)127.0.0.1 only
5540Redis Insight (unauthenticated)127.0.0.1 only
4213DuckDB UI (on-demand, dev build only)127.0.0.1 only
  • Local browsing / VS Code / Cursor: https://localhost:8443 or http://localhost:8880.
  • Remote test machines / extra daemons: give your development host a hostname (for example https://dev.lan:8443 or your LAN IP) so clients are not stuck on localhost. Ports 80 / 443 / 8443 / 8880 / 8081 / 8088 / 19820 listen on all host interfaces.
  • Studio / Mailpit / Redis Insight / DuckDB UI stay loopback-only on purpose — those UIs are unauthenticated. Open Drizzle Studio at https://local.drizzle.studio?host=localhost&port=4983.
  • Tenant sites: http://localhost and https://localhost (ports 80 / 443) reach hosting Caddy after a deploy. On Linux those host binds are privileged — the libvirt tunnel supervisor uses passwordless sudo -n, or you can lower net.ipv4.ip_unprivileged_port_start.

Dev console areas

Use / to switch areas in ./console (ActiveArea = "developer" | "services" | "bootstrap" — bootstrap is the transient provisioning overlay, not a persistent tab):

AreaContents
ServicesService list/detail, restart, runtime switch (Deno/Workers)
DeveloperFleet, database, shell, Converge / re-converge, cell trace

In the Developer area: ↑↓ picks a section, Enter opens it, Esc returns to the section list.

Instance runtime modes

TURBOPANEL_INSTANCE_RUNTIME in /etc/turbopanel/daemon.env selects how the instance runs locally. Switch via the Services area in the console.

ModeBehaviour
deno (default)turbopanel-instance systemd unit runs Deno + Unix socket at /run/turbopanel/instance.sock
workersSame systemd unit runs wrangler dev (scripts/workers-serve.sh) with Postgres on TCP (127.0.0.1:5432)

Workers mode has no Redis. Converge generates the runtime env for both modes (including the local Hyperdrive connection string) under /etc/turbopanel/instance/ — no manual .dev.vars editing is needed.

Guest filesystem (after converge)

PLAINTEXT
~/dev/ ~/turbopaneld/ ~/turbopanel/ ~/ui/ ~/website/ ~/.github/   # mounted checkouts

/opt/turbopanel/vendor/   # pinned Node, Deno, Caddy, uv, Ansible, …
/etc/turbopanel/          # config (dev-user-owned)
/var/lib/turbopanel/      # state (dev-user-owned)
/var/log/turbopanel/      # service logs (dev-user-owned)
/run/turbopanel/          # runtime sockets (dev-user-owned)

Common tasks

Database schema

TurboPanel ships versioned SQL migrations in turbopanel/migrations/. Co-located dev converge and Workers deploy apply them via pnpm migrate. For quick Deno-only iteration without committing migration files, use drizzle-kit push from the guest dev checkout:

Terminal
./scripts/sync.sh          # push instance schema.ts → Postgres (interactive)
./scripts/sync.sh --force  # skip destructive-change prompts (dev only)
./scripts/introspect.sh    # pull live DB → instance schema.ts

For errors and resets, see Database troubleshooting. The dev console Database section can reset the dev instance or start Drizzle Studio.

Formatting

Each repo formats independently — run the formatter configured in that repo before committing.

Workflow diagram

Diagram will load when scrolled into view
Edit on GitHub

Last updated on

On this page