Skylex is a self-hosted database control plane. It automates provisioning, replication, backups, and high availability for PostgreSQL clusters — without handing your data to a cloud vendor.

Two binaries make up the system:

  • skylex-server — the control plane: REST/gRPC API, job scheduler, metadata store (embedded SQLite default, PostgreSQL for HA), and cluster state management.
  • skylex-agent — runs on each database node, executes commands from the server, and reports health/status back over gRPC.

Architecture:

Web UI + REST/gRPC API
       |
skylex-server (SQLite or PostgreSQL metadata, scheduler)
       | gRPC
skylex-agent-1    skylex-agent-2    skylex-agent-3
(PostgreSQL 16)   (PostgreSQL 16)   (PostgreSQL 16)
       |               |               |
       +--- etcd (HA/leader election) ---+
       +--- MinIO (S3 backups via pgBackRest) ---+

PostgreSQL is the only engine in the MVP. MySQL, MongoDB, and Redis are planned for later.

Minimum requirements

  • Go 1.26.1 — build the server and agent
  • Node.js 20+ — build and run the UI
  • Docker Compose v2 — run the full reference stack (server, 3 agents, etcd, MinIO)
  • PostgreSQL 16 — on agent nodes (Docker Compose handles this)

Quick start

1. Clone and build

git clone https://github.com/zhinea/skylex.git
cd skylex
make build

2. Run the server

# SQLite metadata (default, no external DB needed)
make dev

The server starts on:

Port Service
8080 HTTP API
9090 gRPC API
9091 Metrics + health

Health check: curl http://localhost:9091/health

3. UI development

cd ui
npm install
npm run dev

The UI dev server runs on http://localhost:5173.

4. Full stack with Docker Compose

make docker-up        # server + 3 agents + etcd + MinIO
make docker-logs      # follow logs
make docker-down      # tear down

MinIO console: http://localhost:9001 (minioadmin / minioadmin)

Deployment modes

Production HA (PostgreSQL metadata)

For production deployments, run the control plane metadata on PostgreSQL:

# Start PostgreSQL metadata container
docker compose -f deploy/docker-compose/docker-compose.yaml \
               -f deploy/docker-compose/docker-compose.postgres.yaml up -d

# Configure the server for PostgreSQL
export SKYLEX_DATABASE_DRIVER=postgres
export SKYLEX_DATABASE_DSN="postgres://skylex:skylex@localhost:5432/skylex?sslmode=disable"
export SKYLEX_DATABASE_MAX_OPEN_CONNS=25
export SKYLEX_DATABASE_MAX_IDLE_CONNS=10
export SKYLEX_DATABASE_CONN_MAX_LIFETIME=30m

make dev

Systemd (bare metal)

# Install binaries
cp bin/skylex-server /usr/local/bin/
cp bin/skylex-agent /usr/local/bin/

# Install unit files
cp deploy/systemd/skylex-server.service /etc/systemd/system/
cp deploy/systemd/skylex-agent.service /etc/systemd/system/

# Create service user
useradd -r -s /bin/false skylex
mkdir -p /var/lib/skylex /var/log/skylex
chown -R skylex:skylex /var/lib/skylex /var/log/skylex

# Place config at /etc/skylex/config.yaml

systemctl daemon-reload
systemctl enable --now skylex-server

Kubernetes (Helm)

helm install skylex deploy/helm/skylex \
  --set postgresMetadata.enabled=true \
  --set postgresMetadata.password=$(openssl rand -hex 16)

Configuration

The server reads a YAML config file. config.example.yaml is committed and works as-is for local development. Settings can be overridden with environment variables prefixed with SKYLEX_ (e.g. SKYLEX_AUTH_JWT_SECRET).

Key settings

Config path Env var Default
database.driver SKYLEX_DATABASE_DRIVER sqlite3
database.dsn SKYLEX_DATABASE_DSN SQLite WAL
database.max_open_conns SKYLEX_DATABASE_MAX_OPEN_CONNS 1 (SQLite), 25 (PG)
database.max_idle_conns SKYLEX_DATABASE_MAX_IDLE_CONNS 1 (SQLite), 10 (PG)
auth.jwt_secret SKYLEX_AUTH_JWT_SECRET auto-generated
tls.enabled SKYLEX_TLS_ENABLED false

Docker Compose env vars

Env var Use
SKYLEX_JWT_SECRET JWT signing secret
SKYLEX_AGENT_TOKEN Agent authentication token
MINIO_ACCESS_KEY MinIO access key
MINIO_SECRET_KEY MinIO secret key

Performance benchmarking

# Login to get a JWT token
grpcurl -plaintext -d '{"email":"[email protected]","password":"admin"}' \
  localhost:9090 skylex.v1.AuthService/Login

# Run benchmark with token
bin/skylex-bench -addr localhost:9090 \
  -token "YOUR_JWT_TOKEN" \
  -n 100 -c 50

Options: -n total clusters, -c concurrency, -addr gRPC address, -token JWT.

Project layout

cmd/server              skylex-server binary
cmd/agent               skylex-agent binary
cmd/bench               performance benchmarking tool
internal/server         API, auth, scheduler, state machines
internal/agent          agent daemon logic
internal/backup         pgBackRest integration
internal/db             metadata store (SQLite + PostgreSQL) and migrations
internal/dcs            etcd client wrappers
internal/postgres       PG lifecycle management
internal/crypto         encryption and key management
proto/skylex/v1         protobuf service definitions
gen/                    generated Go code (buf, do not hand-edit)
ui/                     Vite + React Router 7 + Tailwind CSS v4
deploy/docker-compose   reference Docker Compose deployment
deploy/systemd          systemd unit files
deploy/helm/skylex      Helm chart scaffold

Migrations

Migrations are embedded in internal/db/migrations/ with separate directories for sqlite and postgres. They are applied automatically on server startup. The migration table is schema_migrations.