Deployment Modes
bext supports three deployment modes that cover everything from a single side project to a globally distributed fleet. Each mode uses the same binary -- only the configuration changes.
Single-App Mode (Default)
The simplest way to run bext. Point it at a directory containing your framework app and it handles the rest: detection, build, and serving.
bext run .
bext reads bext.config.toml from the project root. A minimal config is all you need:
[server]
listen = "0.0.0.0:3061"
static_dir = "./dist/static"
[cache.isr]
default_ttl_ms = 60000
default_swr_ms = 3600000
Single-app mode is the right choice when you are deploying one application per server or container. It is also what bext dev uses during development. The entire request lifecycle -- TLS termination, compression, SSR, caching -- happens inside the single process with zero inter-process overhead.
When to use: solo projects, microservices behind a load balancer, Docker/Kubernetes pods where each replica runs one app.
Multi-App Mode (Virtual Hosts)
When you need to serve multiple applications from one bext instance, switch to multi-app mode. Define each app in the [apps] table of a platform.toml file and start with bext serve:
bext serve --config platform.toml
[platform]
listen = "0.0.0.0:443"
data_dir = "/var/lib/bext"
max_apps = 50
[apps.marketing]
source = "/srv/marketing"
domains = ["example.com", "www.example.com"]
runtime = "nextjs"
[apps.marketing.cache]
default_ttl = "60s"
max_entries = 10000
[apps.blog]
source = "/srv/blog"
domains = ["blog.example.com"]
runtime = "hono"
[apps.blog.cache]
default_ttl = "300s"
[apps.api]
source = "/srv/api"
domains = ["api.example.com"]
runtime = "express"
bext routes incoming requests by matching the Host header against each app's domains list using a trie-based virtual host router. Each app gets its own ISR cache namespace, rate limiter, worker pool, and optional per-app plugin configuration.
Per-app settings you can customize:
| Setting | Description |
|---|---|
cache.default_ttl |
ISR cache TTL for this app |
cache.max_entries |
Max ISR entries before LRU eviction |
rate_limit.rpm |
Requests per minute cap |
isolate.workers |
Number of SSR workers |
isolate.memory_limit |
Max memory per worker (e.g., "256mb") |
deploy.keep_versions |
How many previous versions to keep |
hooks.pre_build |
Shell command to run before build |
hooks.post_deploy |
Shell command to run after deploy |
When to use: hosting multiple sites on a single VPS, internal platform-as-a-service, staging environments where several feature branches share one server.
Edge Mode (Distributed with Redis L2)
Edge mode extends multi-app or single-app mode with a shared Redis backend for cache synchronization across multiple bext instances. This is a Pro feature.
[server]
listen = "0.0.0.0:443"
[redis]
url = "redis://redis.internal:6379"
prefix = "bext:"
[cache.isr]
max_entries = 50000
default_ttl_ms = 60000
default_swr_ms = 3600000
When the [redis] section is present and url resolves, bext activates cluster mode:
- L1 + L2 tiered cache -- in-memory DashMap as L1, Redis as L2. L2 hits are promoted to L1 automatically.
- Distributed invalidation -- cache tag invalidation is broadcast over Redis Pub/Sub so all instances purge simultaneously.
- Shared rate limiting -- rate limit counters use Redis INCR so the limit applies across your entire fleet, not per-instance.
- Write-through consistency -- every ISR cache write is persisted to Redis synchronously (configurable).
When Redis is unreachable, bext degrades gracefully: L1 continues to serve cached content and new renders still work. Reconnection is automatic.
# Instance A (us-east)
REDIS_URL=redis://redis.internal:6379 bext run .
# Instance B (eu-west)
REDIS_URL=redis://redis.internal:6379 bext run .
Both instances share the same cache. A page rendered by Instance A is immediately available to Instance B via the Redis L2 layer.
When to use: multi-region deployments behind a global load balancer, high-availability setups where cache coherence matters, any deployment where you need horizontal scaling beyond a single server.
Choosing the Right Mode
| Consideration | Single-App | Multi-App | Edge |
|---|---|---|---|
| Number of apps | 1 | Many | 1 or many |
| Servers | 1 | 1 | 2+ |
| Cache shared across instances | No | N/A | Yes |
| Redis required | No | No | Yes |
| License tier | Community | Community | Pro |
| Config file | bext.config.toml |
platform.toml |
bext.config.toml + [redis] |
You can always start with single-app mode and migrate to multi-app or edge mode later -- the bext.config.toml settings carry over unchanged.