Docs / Core Concepts / Apps & Services

Apps & Services

Apps are the deployable units within a stack. Each app runs as one or more services (containers). Understanding this relationship is key to managing your deployments effectively.

Apps vs Services

In sh0, the distinction between an app and a service is important:

App

An app is a configuration -- it defines what to deploy, from which source (Git, image, template), with what settings (env vars, domains, resource limits). An app is a persistent entity that survives across deployments.

Service

A service is a running instance -- the actual Docker container created from a deployment. Services are ephemeral. Each deployment creates a new service and (after health checks pass) removes the old one.

Think of an app as the blueprint and a service as the running building. When you redeploy an app, sh0 creates a new service from the updated blueprint, verifies it works, and then tears down the old service.

Diagram showing an App box containing configuration (Git URL, env vars, domain), with arrows pointing to Service v1 (old, being removed) and Service v2 (new, running)
Apps persist across deployments; services are recreated each time

App Lifecycle

An app moves through several states during its lifecycle, from creation to active deployment:

Lifecycle States

StateBadgeDescription
CreatedGrayApp is configured but has never been deployed.
BuildingBlueSource code is being cloned and the container image is being built.
DeployingYellowContainer is starting and health checks are running.
RunningGreenApp is live and serving traffic. Health checks are passing.
StoppedGrayApp was manually stopped. Container is not running.
FailedRedBuild or deployment failed. Previous version continues running if available.
App list showing apps in different states: 'frontend' with a green Running badge, 'worker' with a yellow Deploying badge, and 'migration-job' with a gray Stopped badge
Apps display their current lifecycle state
Zero-Downtime Deploys
When an app is in the Running state and you trigger a new deployment, sh0 uses a blue-green strategy. The old service continues handling traffic while the new one builds and starts. Traffic only switches after the new service passes its health check. If the new service fails, the old one remains active.

Creating an App

Apps are created inside a stack. Navigate to a stack and click Add App. You can create apps from three sources:

  • Git Repository -- Provide a URL, and sh0 clones, detects the stack, builds, and deploys automatically.
  • Docker Image -- Pull and run an existing image from Docker Hub, GitHub Container Registry, or any private registry.
  • Template -- Choose from 170+ pre-configured templates for popular applications.
Add App dialog showing three source options as cards: Git Repository with a branch icon, Docker Image with a container icon, and Template with a grid icon
Choose your app source

App Settings

Each app has a comprehensive settings panel organized into several categories.

General Settings

  • Name -- The app's identifier within the stack. Also used as the Docker container name and internal hostname.
  • Port -- The port your application listens on inside the container. sh0 routes external traffic to this port.
  • Source -- The Git URL, Docker image, or template configuration.
  • Branch -- For Git-based apps, the branch to track and deploy from.
  • Auto-deploy -- When enabled, pushes to the tracked branch trigger automatic deployments.

Build Settings

  • Build Command -- Override the default build command (e.g., npm run build).
  • Start Command -- Override the default start command (e.g., node server.js).
  • Dockerfile Path -- Use a custom Dockerfile instead of sh0's auto-generated one.
  • Build Arguments -- Pass build-time variables to the Docker build process.
App settings page showing the Build Settings section with fields for Build Command, Start Command, Dockerfile Path, and Build Arguments
Customizing build and start commands

Resource Limits

You can set CPU and memory limits on each app to prevent a single application from consuming all server resources:

SettingDefaultDescription
CPU LimitNo limitMaximum CPU cores the container can use (e.g., 0.5, 1, 2)
Memory LimitNo limitMaximum RAM (e.g., 256m, 512m, 1g). Container is killed if exceeded.
Memory ReservationNo limitSoft limit. Docker tries to keep the container near this value.
Setting Limits via API
curl -X PUT http://localhost:9000/api/apps/APP_ID \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cpu_limit": 1.0, "memory_limit": "512m"}'
Out of Memory
When a container exceeds its memory limit, Docker kills it immediately (OOMKilled). If your app frequently hits the limit, increase the allocation or investigate memory leaks. Check the Monitoring section for memory usage graphs.

Restart Policies

Restart policies determine what happens when a container stops or crashes:

PolicyBehavior
alwaysAlways restart the container, regardless of exit code. Default for apps.
on-failureOnly restart if the container exits with a non-zero exit code.
unless-stoppedRestart unless explicitly stopped by the user.
noNever restart. Useful for one-off tasks like migrations.
Tip
For long-running services (web servers, APIs), use always. For one-off jobs (database migrations, seed scripts), use no so the container stops after the task completes.

Health Checks

Health checks verify that your app is working correctly after deployment. sh0 supports two types:

  • HTTP Health Check -- sh0 sends an HTTP GET request to a specified path (default: /) and expects a 2xx response.
  • TCP Health Check -- sh0 verifies the container is listening on the configured port. Used for non-HTTP services.
Health Check Configuration
{"health_check": {"type": "http", "path": "/health", "interval": 10, "timeout": 5, "retries": 3, "start_period": 30}}
App health check settings showing type selector (HTTP/TCP), path field, interval, timeout, retries, and start period fields with sensible defaults
Configuring health checks for your app
Note
During deployment, sh0 waits for the health check to pass before routing traffic to the new container. If the health check fails after the configured retries, the deployment is marked as failed and the previous version continues serving traffic.