Skip to main content

Tech stack

StellarStack is built with modern, production-grade technologies chosen for performance, developer experience, and long-term maintainability.

Backend (API)

The API server handles authentication, permissions, and orchestration.

Hono

Hono

Ultrafast web framework for the Edge (~40,000 req/s)
Why Hono?
  • Extremely fast routing and request handling
  • TypeScript-first with excellent type inference
  • Lightweight (no dependencies, ~12KB)
  • Works on Node.js, Bun, Deno, and Edge runtimes
  • Middleware ecosystem (CORS, logger, rate limiting)
// From apps/api/src/index.ts
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";

const app = new Hono();

app.use("*", logger());
app.use("/api/*", cors({ origin: FRONTEND_URL, credentials: true }));

app.get("/health", (c) => {
  return c.json({ status: "ok", timestamp: new Date().toISOString() });
});

Better Auth

Better Auth

Modern authentication library with OAuth, 2FA, and passkeys
Features:
  • Email/password authentication with bcrypt hashing
  • OAuth providers (Google, GitHub, Discord)
  • Two-factor authentication (TOTP)
  • Passkey support (WebAuthn)
  • Session management with secure HTTP-only cookies
  • TypeScript-first API
// From apps/api/src/lib/auth.ts
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { passkey } from "@better-auth/passkey";

export const auth = betterAuth({
  database: prismaAdapter(db, { provider: "postgresql" }),
  emailAndPassword: {
    enabled: true,
    minPasswordLength: 8,
    requireEmailVerification: true,
  },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    },
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    },
    discord: {
      clientId: process.env.DISCORD_CLIENT_ID!,
      clientSecret: process.env.DISCORD_CLIENT_SECRET!,
    },
  },
  plugins: [passkey()],
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
    updateAge: 60 * 60 * 24, // 1 day
  },
});

Prisma ORM

Prisma

Type-safe ORM with automatic migrations for PostgreSQL
Why Prisma?
  • Full TypeScript type safety
  • Intuitive data modeling with Prisma Schema
  • Automatic migrations
  • Query builder prevents SQL injection
  • Excellent developer experience with Prisma Studio
// From apps/api/prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id               String   @id @default(cuid())
  name             String
  email            String   @unique
  emailVerified    Boolean  @default(false)
  role             String   @default("user")
  banned           Boolean  @default(false)
  twoFactorEnabled Boolean  @default(false)
  createdAt        DateTime @default(now())
  updatedAt        DateTime @updatedAt

  sessions   Session[]
  accounts   Account[]
  servers    Server[]
  webhooks   Webhook[]
  
  serverMemberships   ServerMember[]
  sentInvitations     ServerInvitation[] @relation("SentInvitations")
  receivedInvitations ServerInvitation[] @relation("ReceivedInvitations")

  @@map("users")
}

WebSocket

@hono/node-ws

WebSocket support for Hono on Node.js
Real-time console output and server statistics stream via WebSocket:
// From apps/api/src/index.ts
import { createNodeWebSocket } from "@hono/node-ws";

const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });

// WebSocket route for console streaming
app.get(
  "/api/ws/console/:serverId",
  upgradeWebSocket((c) => {
    const serverId = c.req.param("serverId");
    
    return {
      onOpen(evt, ws) {
        console.log(`[WS] Client connected to server ${serverId}`);
        wsManager.subscribe(serverId, ws);
      },
      onMessage(evt, ws) {
        const data = JSON.parse(evt.data.toString());
        if (data.type === "command") {
          // Forward command to daemon
          forwardCommandToDaemon(serverId, data.command);
        }
      },
      onClose(evt, ws) {
        wsManager.unsubscribe(serverId, ws);
      },
    };
  })
);

Dependencies

// From apps/api/package.json
{
  "dependencies": {
    "@hono/node-server": "^1.13.7",
    "@hono/node-ws": "^1.2.0",
    "@prisma/client": "6.19.2",
    "@better-auth/passkey": "^1.4.9",
    "bcrypt": "^6.0.0",
    "better-auth": "^1.1.14",
    "hono": "^4.6.16",
    "jsonwebtoken": "^9.0.3",
    "nodemailer": "^7.0.12",
    "ws": "^8.18.3",
    "zod": "^3.24.1"
  }
}

Frontend (Web Panel)

The web panel provides a real-time dashboard built with React and Next.js.

Next.js 15

Next.js 15

React framework with App Router and Server Components
Why Next.js 15?
  • App Router with React Server Components
  • Server-side rendering for fast initial page loads
  • API routes for backend-for-frontend patterns
  • Built-in image optimization
  • Turbopack for faster dev builds
// From apps/web/package.json
{
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "^15.5.9",
    "react": "^19.2.1",
    "react-dom": "^19.2.1"
  }
}

React 19

React 19

UI library with Server Components and improved performance
New features:
  • Server Components for zero-bundle-size data fetching
  • Actions for form handling
  • use() hook for async data
  • Improved hydration and error handling
// From apps/web/app/servers/page.tsx (conceptual)
import { Suspense } from 'react';

async function ServerList() {
  const servers = await fetch('http://localhost:3001/api/servers').then(r => r.json());
  
  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
      {servers.map(server => (
        <ServerCard key={server.id} server={server} />
      ))}
    </div>
  );
}

export default function ServersPage() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <ServerList />
    </Suspense>
  );
}

Tailwind CSS

Tailwind CSS

Utility-first CSS framework for rapid UI development
Why Tailwind?
  • Utility classes for fast prototyping
  • No CSS-in-JS runtime overhead
  • Automatic purging of unused styles
  • Excellent design system with spacing, colors, and typography
  • Dark mode support out of the box
// Example component with Tailwind
export function ServerCard({ server }) {
  return (
    <div className="rounded-lg border bg-card text-card-foreground shadow-sm">
      <div className="p-6 flex flex-col gap-4">
        <div className="flex items-center justify-between">
          <h3 className="text-lg font-semibold">{server.name}</h3>
          <StatusBadge status={server.status} />
        </div>
        <div className="text-sm text-muted-foreground">
          <p>CPU: {server.cpu}%</p>
          <p>Memory: {server.memory} MB</p>
        </div>
      </div>
    </div>
  );
}

shadcn/ui

shadcn/ui

Accessible component library built with Radix UI and Tailwind
Components used:
  • Button, Input, Textarea, Select, Checkbox
  • Dialog, Sheet, Dropdown Menu, Popover
  • Table, Tabs, Accordion, Alert
  • Card, Badge, Avatar, Skeleton
// From apps/web/components/ui/button.tsx (simplified)
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";

const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline: "border border-input bg-background hover:bg-accent",
        ghost: "hover:bg-accent hover:text-accent-foreground",
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 px-3",
        lg: "h-11 px-8",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
);

TanStack Query

TanStack Query

Powerful data fetching and caching library
Features:
  • Automatic background refetching
  • Request deduplication
  • Optimistic updates
  • Infinite queries for pagination
  • DevTools for debugging
// From apps/web/hooks/useServers.ts (conceptual)
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

export function useServers() {
  return useQuery({
    queryKey: ['servers'],
    queryFn: async () => {
      const res = await fetch('/api/servers');
      if (!res.ok) throw new Error('Failed to fetch servers');
      return res.json();
    },
    refetchInterval: 5000, // Refetch every 5 seconds
  });
}

export function useStartServer() {
  const queryClient = useQueryClient();
  
  return useMutation({
    mutationFn: async (serverId: string) => {
      const res = await fetch(`/api/servers/${serverId}/power`, {
        method: 'POST',
        body: JSON.stringify({ action: 'start' }),
      });
      if (!res.ok) throw new Error('Failed to start server');
      return res.json();
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['servers'] });
    },
  });
}

Dependencies

// From apps/web/package.json (selected)
{
  "dependencies": {
    "next": "^15.5.9",
    "react": "^19.2.1",
    "react-dom": "^19.2.1",
    "@tanstack/react-query": "^5.90.12",
    "@tanstack/react-table": "^8.21.3",
    "better-auth": "^1.1.14",
    "framer-motion": "^12.23.25",
    "lucide-react": "^0.68.0",
    "next-themes": "^0.4.6",
    "react-hook-form": "^7.71.0",
    "recharts": "2.15.4",
    "sonner": "^2.0.7",
    "zod": "^4.3.5",
    "zustand": "^5.0.9"
  }
}

Daemon (Nodes)

The daemon runs on each physical server and manages Docker containers.

Rust

Rust

Systems programming language for performance and safety
Why Rust?
  • Memory safety without garbage collection
  • Zero-cost abstractions
  • Fearless concurrency with ownership system
  • Excellent performance (comparable to C/C++)
  • Rich ecosystem with Cargo package manager

Docker (Bollard)

Bollard

Async Docker API client for Rust
Container operations:
  • Create, start, stop, restart, kill containers
  • Stream logs in real-time
  • Execute commands inside containers
  • Monitor resource usage (CPU, memory, network)
  • Manage volumes and networks
# From apps/daemon/Cargo.toml
[dependencies]
bollard = "0.17"

Tokio

Tokio

Async runtime for building fast, reliable network applications
Features:
  • Multi-threaded work-stealing scheduler
  • Async I/O with zero-cost futures
  • Timers and intervals for task scheduling
  • Channels for message passing
  • Synchronization primitives (Mutex, RwLock, Semaphore)
# From apps/daemon/Cargo.toml
[dependencies]
tokio = { version = "1", features = ["full", "sync", "parking_lot"] }
tokio-util = { version = "0.7", features = ["io", "codec", "rt"] }

Axum

Axum

Ergonomic web framework built on Tokio and Hyper
Why Axum?
  • Built by the Tokio team
  • Type-safe routing with extractors
  • WebSocket support
  • Tower middleware ecosystem
  • Excellent compile-time error messages
# From apps/daemon/Cargo.toml
[dependencies]
axum = { version = "0.7", features = ["ws", "multipart", "tokio"] }
axum-extra = { version = "0.9", features = ["typed-header"] }
tower = "0.4"
tower-http = { version = "0.5", features = ["cors", "trace", "request-id", "timeout"] }

SFTP Server (russh)

russh

SSH and SFTP server implementation in Rust
Provides SFTP access for file transfers:
# From apps/daemon/Cargo.toml
[dependencies]
russh = "0.46"
russh-sftp = "2.0"
russh-keys = "0.46"

Key Dependencies

tokio = { version = "1", features = ["full", "sync", "parking_lot"] }
tokio-util = { version = "0.7", features = ["io", "codec", "rt"] }
futures = "0.3"
futures-util = "0.3"
async-trait = "0.1"

Infrastructure

Monorepo tooling and development infrastructure.

pnpm

pnpm

Fast, disk-efficient package manager
Why pnpm?
  • Uses a content-addressable store (saves disk space)
  • Strict dependency resolution (prevents phantom dependencies)
  • Up to 2x faster than npm
  • Native monorepo support with workspaces
// From package.json
{
  "packageManager": "[email protected]",
  "engines": {
    "node": ">=20"
  }
}

Turborepo

Turborepo

High-performance build system for monorepos
Features:
  • Intelligent task caching
  • Parallel execution with dependency awareness
  • Remote caching for CI/CD
  • Incremental builds
// From package.json
{
  "scripts": {
    "build": "turbo build",
    "dev": "turbo dev",
    "lint": "turbo lint",
    "typecheck": "turbo typecheck"
  },
  "devDependencies": {
    "turbo": "^2.5.5"
  }
}

PostgreSQL

PostgreSQL

Advanced open-source relational database
Why PostgreSQL?
  • ACID compliance and strong consistency
  • Excellent JSON support (jsonb type)
  • Full-text search capabilities
  • Mature ecosystem with great tooling
  • Horizontal scaling with read replicas

Docker Compose

Docker Compose

Multi-container orchestration for local development
Simplifies running the full stack locally:
# docker-compose.yml (conceptual)
version: '3.8'

services:
  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: stellarstack
      POSTGRES_USER: stellarstack
      POSTGRES_PASSWORD: stellarstack
    ports:
      - "5432:5432"
    volumes:
      - postgres-data:/var/lib/postgresql/data
  
  api:
    build: ./apps/api
    environment:
      DATABASE_URL: postgresql://stellarstack:stellarstack@postgres:5432/stellarstack
      BETTER_AUTH_SECRET: dev-secret-change-in-production
    ports:
      - "3001:3001"
    depends_on:
      - postgres
  
  web:
    build: ./apps/web
    environment:
      NEXT_PUBLIC_API_URL: http://localhost:3001
    ports:
      - "3000:3000"
    depends_on:
      - api

volumes:
  postgres-data:

DevOps

GitHub Actions

GitHub Actions

CI/CD for automated testing, building, and deployment
Workflows:
  • Docker image builds for API, web, and daemon
  • Automated releases with changelog generation
  • Linting and type checking on PRs
  • Dependency updates with Dependabot

release-please

release-please

Automated changelog and version management
Features:
  • Parses Conventional Commits to determine version bump
  • Generates changelog from commit messages
  • Creates GitHub releases automatically
  • Supports monorepos with independent versioning

commitlint

commitlint

Enforces Conventional Commit format
// From package.json
{
  "devDependencies": {
    "@commitlint/cli": "^20.3.1",
    "@commitlint/config-conventional": "^20.3.1",
    "husky": "^9.1.7",
    "lint-staged": "^16.2.7"
  }
}
Commit format:
feat: STE-123 add user authentication
fix: STE-456 resolve database connection timeout
docs: STE-789 update installation guide

Security

StellarStack takes security seriously with multiple layers of protection.

bcrypt password hashing

Industry-standard hashing with cost factor 10

AES-256-CBC encryption

For sensitive data at rest (API keys, tokens)

Rate limiting

Protection against brute-force attacks

CSRF protection

All state-changing requests require CSRF tokens

Security headers

CSP, X-Frame-Options, HSTS, X-Content-Type-Options

Docker isolation

Each game server runs in its own container

Version information

Current version: 1.3.9 (Alpha)Version is managed automatically by release-please based on Conventional Commits.
// From package.json
{
  "name": "stellarstack",
  "version": "1.3.9",
  "private": true
}

Next steps

How It Works

Learn about the daemon-per-node architecture

Installation

Get StellarStack running on your infrastructure

Build docs developers (and LLMs) love