Skip to content

Architecture

This page explains Stackpad’s core architecture and the mental model behind how your applications are organized and deployed.

Resource hierarchy

Organization
└── Project (services sharing a private Docker network)
├── Environment (e.g. production, staging)
│ ├── Service: web → Next.js app, exposed via HTTPS
│ ├── Service: database → PostgreSQL, internal only
│ ├── Service: cache → Redis, internal only
│ └── Service: worker → Background jobs, internal only
│ └── Deployment → A single deploy: build → container → health check
└── Environment (e.g. staging)
└── ... (same services, different containers)

Organizations

The top-level entity. An organization represents a team with a billing plan, members, and projects. All resources and costs are scoped to an organization.

Projects

A project is a stack of related services that share a private Docker network. Think of it as one application — your web frontend, database, cache, and background workers all live in one project.

Environments

Each project has one or more environments. The default environment deploys from your main branch. You can add staging environments, or enable catch-all environments for automatic preview deployments from pull request branches.

Services

A service is a single container. Services have a type that determines their default behavior:

TypeExposed externallyAuto-backupExample
WebYes (HTTPS)NoNext.js, Express
DatabaseNoYesPostgreSQL, MariaDB
CacheNoYesRedis, Valkey
ServiceNoNoWorkers, cron jobs

Deployments

A deployment is a single version of a service. When you push code or trigger a manual deploy, a new deployment is created. It goes through: queued → building → deploying → ready (or failed).

Infrastructure nodes

Stackpad’s infrastructure consists of specialized node types:

┌─────────────────────────┐
│ CONTROL NODE │
│ Caddy, API, Dashboard │
│ PostgreSQL, ClickHouse │
│ Docker Registry │
└───────────┬─────────────┘
Private Network (WireGuard)
┌─────────┼─────────┐
│ │ │
┌─┴──────┐ ┌┴──────┐ ┌┴──────┐
│ BUILD │ │COMPUTE│ │COMPUTE│
│ NODE │ │NODE 1 │ │NODE 2 │
│ Builds │ │Runs │ │Runs │
│ images │ │your │ │your │
│ │ │apps │ │apps │
└────────┘ └───────┘ └───────┘
  • Control node — runs the Stackpad platform itself: API, dashboard, reverse proxy (Caddy), database, logs
  • Build nodes — dedicated to building Docker images from your source code
  • Compute nodes — run your application containers

All nodes run on Hetzner Cloud across multiple European locations. They communicate over a private WireGuard network.

Deployment pipeline

When you push to your deployment branch:

  1. GitHub webhook → Stackpad API receives the push event
  2. Queue → deployment is queued (max 4 concurrent builds per build node)
  3. Clone → repository is cloned on the build node
  4. Detect → framework is auto-detected from package.json
  5. Build → Docker image is built using BuildKit
  6. Push → image is pushed to the private registry on the control node
  7. Pull → compute node pulls the image
  8. Start → new container starts alongside the old one
  9. Health check → Stackpad verifies the new container responds
  10. Switch → Caddy routes traffic to the new container
  11. Stop → old container is stopped

This process achieves zero-downtime deployments with automatic rollback on failure.

Reverse proxy

Caddy serves as the reverse proxy and handles:

  • HTTPS termination with automatic Let’s Encrypt certificates
  • Dynamic routing — routes are added/removed via Caddy’s admin API without restarts
  • Load balancing — traffic is routed to the correct compute node and container
  • Custom domains — CNAME and A record verification, automatic certificate provisioning

Observability

Logs from all containers are collected by Vector, enriched with metadata (organization, project, service), and stored in ClickHouse for fast querying and full-text search.

What’s next?