Skip to content

App Model

App Model

How Pvdify organizes applications.

App Slot

An App Slot is the fundamental deployment unit. Each slot represents one running instance of an application in a specific environment.

Schema

name: myapp # Unique identifier
environment: production # production | staging | preview
image: ghcr.io/org/app:v1.2.3 # Container image
processes:
web:
command: "npm start"
count: 1
worker:
command: "npm run worker"
count: 1
bind_port: 3001 # Internal port (3000+)
domains:
- myapp.com
- www.myapp.com
env_versions:
- v1: { created: "2026-01-01", hash: "abc123" }
- v2: { created: "2026-01-05", hash: "def456" }
resources:
memory: 512M # Memory limit
cpu: 0.5 # CPU shares
healthcheck:
path: /health
interval: 30s
timeout: 5s

Fields

FieldTypeRequiredDescription
namestringUnique app identifier (lowercase, alphanumeric, hyphens)
environmentenumproduction, staging, or preview
imagestringFull container image reference
processesmapProcess type definitions
bind_portintInternal port (auto-assigned from 3000+)
domains[]stringCustom domain list
env_versions[]objectConfig version history
resourcesobjectMemory/CPU limits
healthcheckobjectHealth check configuration

Environments

Apps support three environment types:

EnvironmentPurposeLifecycle
productionLive trafficPermanent
stagingPre-production testingPermanent
previewPR previewsEphemeral (auto-cleanup)

Naming Convention

myapp → production
myapp-staging → staging
myapp-pr-123 → preview (auto-generated)

Processes

Each app can define multiple process types:

processes:
web:
command: "node server.js"
count: 2 # Horizontal scaling
worker:
command: "node worker.js"
count: 1
scheduler:
command: "node cron.js"
count: 1

Process Lifecycle

Each process becomes a systemd unit:

pvdify-myapp-web.service
pvdify-myapp-worker.service
pvdify-myapp-scheduler.service

Managed via:

Terminal window
pvdify ps myapp # List processes
pvdify ps:scale web=2 # Scale horizontally
pvdify ps:restart web # Restart process type

Releases

A Release is an immutable deployment snapshot:

release:
version: 42
image: ghcr.io/org/app:v1.2.3
config_version: v2
created_at: 2026-01-05T10:30:00Z
created_by: gh-actions
status: active

Release Lifecycle

  1. Create — New release created via API/CLI
  2. Pending — Image pulled, containers prepared
  3. Deploying — Blue-green swap in progress
  4. Active — Release is serving traffic
  5. Superseded — Replaced by newer release (kept for rollback)

Rollback

Terminal window
# View release history
pvdify releases myapp
# Rollback to previous
pvdify rollback myapp
# Rollback to specific version
pvdify rollback myapp --version 41

Config & Secrets

Environment variables stored separately from releases:

Terminal window
# Set config
pvdify config:set DATABASE_URL=postgres://...
# Set secret (encrypted with SOPS)
pvdify config:set --secret API_KEY=sk_live_...
# View config
pvdify config myapp
# Config versioning
pvdify config:versions myapp

Config Versions

Each config change creates a new version:

env_versions:
- version: v1
created: 2026-01-01T10:00:00Z
hash: abc123
changes: ["DATABASE_URL"]
- version: v2
created: 2026-01-05T10:30:00Z
hash: def456
changes: ["API_KEY", "REDIS_URL"]

Domains

Custom domains attached to app slots:

Terminal window
# Add domain
pvdify domains:add myapp myapp.com
# List domains
pvdify domains myapp
# Remove domain
pvdify domains:remove myapp myapp.com

Domain Resolution

  1. Domain added to app slot
  2. Cloudflare DNS record created (via API)
  3. Cloudflare Tunnel route configured
  4. TLS handled by Cloudflare (Full strict)

Resources

Memory and CPU limits per process:

resources:
memory: 512M # Memory limit (required)
cpu: 0.5 # CPU shares (0.0-1.0)

Resource Defaults

EnvironmentMemoryCPU
production512M0.5
staging256M0.25
preview128M0.1

Health Checks

Liveness probes for process monitoring:

healthcheck:
path: /health # HTTP endpoint
interval: 30s # Check frequency
timeout: 5s # Request timeout
retries: 3 # Failures before restart

Unhealthy containers are automatically restarted by systemd.

Storage

Apps are stateless by design. For persistence:

NeedSolution
DatabaseExternal (PlanetScale, Supabase, Neon)
FilesS3 bucket (AWS)
CacheRedis (if needed)
SessionsCookie-based or Redis

Example: Full App Definition

# myapp production slot
name: myapp
environment: production
image: ghcr.io/acme/myapp:v2.1.0
processes:
web:
command: "node dist/server.js"
count: 2
worker:
command: "node dist/worker.js"
count: 1
bind_port: 3001
domains:
- myapp.com
- www.myapp.com
- api.myapp.com
env_versions:
- version: v3
created: 2026-01-05T10:30:00Z
hash: def456
resources:
memory: 512M
cpu: 0.5
healthcheck:
path: /health
interval: 30s
timeout: 5s
retries: 3