Examples

Step-by-step guides for common deployment scenarios. Each example is self-contained and can be copied directly to your terminal.

Quick Start

Beginner

Deploy Your First Application

The simplest possible deployment: a single service that responds to HTTP requests. The VM boots on the first request and stays warm for subsequent requests.

1

Create a stack with a web service

sf stack create myapp --entrypoint web sf stack add myapp web --image nodetest --tag 0.0.5
2

Test it (first request triggers cold boot)

curl http://web.myapp.localhost.openiap.io
{"message": "Hello from nodejs", "version": "0.0.5"}
3

Check running instances

sf instance list
4

Clean up when done

sf stack delete myapp --force

Production Stack

Intermediate

Always-On Production Environment

Create a production stack with multiple services that run continuously. Each stack is a complete application definition.

1

Create the prod stack with all services

# Create prod stack with frontend as entrypoint sf stack create prod --entrypoint frontend # Add services sf stack add prod db --image postgres --tag 15 sf stack add prod redis --image redis --tag 7 sf stack add prod backend --image myapp/backend --tag v1.0.0 --depends-on db,redis sf stack add prod frontend --image myapp/frontend --tag v1.0.0 --depends-on backend
2

Set environment variables for prod

sf env set DATABASE_URL "postgres://db:5432/app" --match stack=prod sf env set REDIS_URL "redis://redis:6379" --match stack=prod sf env set NODE_ENV "production" --match stack=prod
3

Access services

curl http://frontend.prod.localhost.openiap.io curl http://backend.prod.localhost.openiap.io curl http://db.prod.localhost.openiap.io

Development Stack

Intermediate

Scale-to-Zero Development Environment

Create a separate dev stack that scales to zero when idle. Services boot on first request and shut down after inactivity.

1

Create the dev stack

# Create dev stack (separate from prod) sf stack create dev --entrypoint frontend # Add services (same structure, different tags) sf stack add dev db --image postgres --tag 15 sf stack add dev redis --image redis --tag 7 sf stack add dev backend --image myapp/backend --tag dev --depends-on db,redis sf stack add dev frontend --image myapp/frontend --tag dev --depends-on backend
2

Set dev-specific environment

sf env set DEBUG "true" --match stack=dev sf env set LOG_LEVEL "debug" --match stack=dev sf env set NODE_ENV "development" --match stack=dev
3

Access dev services

curl http://frontend.dev.localhost.openiap.io

Result: Services scale to zero when idle, boot on first request.

PR Preview Environments

Key Concept

Variants: SHARED vs UNIQUE Services

Create PR preview variants that inherit from a stack. Only overridden services are UNIQUE (cost resources) - everything else is SHARED from the parent stack.

1

Create a PR variant from dev stack

# PR 42 only changes frontend sf variant create dev pr-42 --override frontend.tag=pr-42-build
2

What happens (SHARED vs UNIQUE)

Stack DEV ├── db ─── SHARED ──┐ ├── redis ─── SHARED ──┼──> PR-42 uses these (no extra cost!) ├── backend ─── SHARED ──┘ └── frontend └──> PR-42 has UNIQUE frontend (only cost)

Result: PR-42 only pays for ONE service (frontend). Database, Redis, and backend are shared from dev stack.

3

Access the PR preview

# Unique frontend, shared backend services curl http://frontend.dev--pr-42.localhost.openiap.io
4

Clean up after PR merge

sf variant delete dev/pr-42 --force

Multiple PR Variants

Intermediate

Different PRs, Different Overrides

Each PR can override different services. Only overridden services cost resources.

1

Create variants with different overrides

# PR-42: Frontend changes only sf variant create dev pr-42 --override frontend.tag=pr-42 # PR-63: Backend + Database changes (switching to MongoDB) sf variant create dev pr-63 \ --override db.image=mongo --override db.tag=7 \ --override backend.tag=pr-63 # PR-99: Backend and frontend changes sf variant create dev pr-99 \ --override backend.tag=pr-99 \ --override frontend.tag=pr-99
2

Cost breakdown

| Variant | UNIQUE (costs $) | SHARED (free) | |---------|-------------------------|----------------------| | pr-42 | frontend | db, redis, backend | | pr-63 | db, backend | redis, frontend | | pr-99 | backend, frontend | db, redis |

Database with Persistent Storage

Advanced

PostgreSQL with Persistent Volume

Run a PostgreSQL database with persistent storage that survives VM restarts. Data is stored on a volume that gets reattached on cold boot.

1

Create a persistent volume

sf volume create dbvol /var/lib/postgresql/data/pgdata --size 1G
2

Create stack with database service

sf stack create mydb --entrypoint db # Add postgres with volume attached sf stack add mydb db --image postgres --tag 15 \ --volume dbvol:/var/lib/postgresql/data/pgdata \ --min-instances 1 # Keep at least 1 running
3

Verify the database is running

# List instances sf instance list # Check volume is mounted sf instance exec <vm_id> -- ls -la /var/lib/postgresql/data/pgdata
4

Create a backup snapshot

sf volume snapshot create dbvol --name dbvol-backup-1 # List snapshots sf volume snapshot list dbvol

GPU-Accelerated Workload

Advanced

ML Inference with GPU Passthrough

Run GPU-accelerated workloads with automatic hypervisor selection. The system picks QEMU when GPU support is needed.

1

Create a GPU workload

# System auto-selects QEMU for GPU support sf workload create ml-inference --image pytorch:latest --gpus 1
2

Or add GPU service to a stack

sf stack create mlapp --entrypoint inference sf stack add mlapp inference --image pytorch:latest \ --feature gpu \ --min-instances 1
3

Create a VM snapshot for fast warm starts

# Snapshot includes GPU memory state sf instance snapshot <vm_id> --name warm-pytorch # List VM snapshots sf vm-snapshot list

Custom Domains

Intermediate

Set Up Custom Domain with Aliases

Map your own domain names to stack services. After DNS is configured, requests to your domain route directly to the right service.

1

Create aliases for production services

# Main website -> frontend service in prod stack sf alias add www.mycompany.com --stack prod --service frontend # API subdomain -> backend service in prod stack sf alias add api.mycompany.com --stack prod --service backend # Staging -> frontend in dev stack sf alias add staging.mycompany.com --stack dev --service frontend # PR preview alias (optional) sf alias add pr-42.mycompany.com --stack dev --variant pr-42 --service frontend
2

Configure your DNS

Point your domain to the Tidedge load balancer IP or CNAME.

3

Test the aliases

# These should now work curl https://www.mycompany.com curl https://api.mycompany.com/health
4

List and manage aliases

sf alias list sf alias get www.mycompany.com sf alias delete www.mycompany.com --force

Warm Pools for Fast Cold Starts

Advanced

Pre-warm VMs for Instant Scaling

Create pools of pre-warmed VMs that can be instantly converted to service instances when requests arrive. The scheduler matches compatible layer stacks.

1

Create a warm pool with Node.js base

# Keep 3-5 warm VMs ready sf pool create node-pool --image node22:latest --min-warm 3 --max-warm 5
2

Deploy services that use this base

# Any app built on node22 can use the pool sf stack add myapp web --image nodetest --tag 0.0.5 # First request gets a warm VM instead of cold boot! curl http://web.myapp.localhost.openiap.io
3

Monitor pool status

sf pool list sf instance list # Shows "Pool" status for warm VMs

Environment Variables

Key Concept

Variables at Different Levels

Environment variables cascade down and can be overridden at each level. Priority (lowest to highest): image → project → stack → variant → service

1

Set variables at different scopes

# Project-wide (applies to all stacks in project) sf env set COMPANY "Acme Corp" --match project=myproject # Stack-specific sf env set DATABASE_URL "postgres://prod-db:5432/app" --match stack=prod sf env set DATABASE_URL "postgres://dev-db:5432/app" --match stack=dev # Variant-specific (overrides stack setting) sf env set FEATURE_FLAG "experimental" --match variant=pr-42 # Service-specific sf env set PORT "3000" --match service=frontend sf env set PORT "8080" --match service=backend
2

Resolution order

image (Dockerfile ENV) → project → stack [→ variant] → service # Example: frontend service in pr-42 variant of dev stack # Gets: image defaults + project vars + dev stack vars + pr-42 vars + frontend vars
3

List and manage variables

sf env list --match stack=prod sf env get DATABASE_URL --match stack=prod sf env delete DEBUG --match stack=dev

Complete Working Example

Copy & Paste

Full Workflow: Prod + Dev + PR Preview

Complete example showing the recommended setup: production stack, development stack, and PR preview variant with shared services.

# 1. Set up project sf project create myapp sf project use myapp # 2. Create production stack (always-on) sf stack create prod --entrypoint frontend sf stack add prod db --image postgres --tag 15 sf stack add prod redis --image redis --tag 7 sf stack add prod backend --image myapp/backend --tag v1.0.0 --depends-on db,redis sf stack add prod frontend --image myapp/frontend --tag v1.0.0 --depends-on backend # 3. Create development stack (scale-to-zero) sf stack create dev --entrypoint frontend sf stack add dev db --image postgres --tag 15 sf stack add dev redis --image redis --tag 7 sf stack add dev backend --image myapp/backend --tag dev --depends-on db,redis sf stack add dev frontend --image myapp/frontend --tag dev --depends-on backend # 4. Set environment variables sf env set NODE_ENV "production" --match stack=prod sf env set NODE_ENV "development" --match stack=dev sf env set DEBUG "true" --match stack=dev # 5. Create PR preview (only frontend is UNIQUE, rest SHARED from dev) sf variant create dev pr-42 --override frontend.tag=pr-42 # 6. Access everything echo "Production:" curl http://frontend.prod.localhost.openiap.io echo "Development:" curl http://frontend.dev.localhost.openiap.io echo "PR Preview (shares db/redis/backend from dev):" curl http://frontend.dev--pr-42.localhost.openiap.io # 7. View what we created sf stack list sf variant list dev # 8. Cleanup sf variant delete dev/pr-42 --force sf stack delete dev --force sf stack delete prod --force echo "Done!"