Deploy
Anywhere
Production-ready deployment patterns for Warp. Multi-region, GDPR-compliant, and battle-tested.
Fly.io with GDPR Data Residency
FeaturedDeploy Warp across multiple regions with geo-aware data residency. User data stays in their home region (EU/US/APAC) while writes can happen from anywhere.
Docker Compose
Coming SoonLocal development and single-node production deployments with Docker Compose.
Kubernetes
Coming SoonStatefulSets, persistent volumes, and horizontal scaling on Kubernetes.
Railway
Coming SoonOne-click deployment with Railway's managed infrastructure.
Fly.io with GDPR Data Residency
Multi-region deployment with geo-aware routing
Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ Client (anywhere) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Fly.io Anycast Edge │
│ (routes to nearest app instance) │
└─────────────────────────────────────────────────────────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│Warp Leader │◄──►│Warp Leader │◄──►│Warp Leader │
│ (ams-1) │ │ (iad-1) │ │ (sin-1) │
│ [EU Data] │ │ [US Data] │ │ [APAC Data] │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ replication │ replication │ replication
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│Warp Replica │ │Warp Replica │ │Warp Replica │
│ (ams-2) │ │ (iad-2) │ │ (sin-2) │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Volume │ │ Volume │ │ Volume │
│ (ams) │ │ (iad) │ │ (sin) │
└─────────────┘ └─────────────┘ └─────────────┘ - Nodes auto-discover via
WARP_CLUSTER_DNS - User data stays in their home region
- Shards rebalance automatically on scale
- Entity IDs encode region:
eu/user/alice
- Leader writes, replicas sync async
- Fire-and-forget (no latency impact)
- Automatic failover on leader death
- Highest sequence wins election
- GDPR compliant data residency
- Zero data loss on failover
- Easy export and deletion per entity
- Add more regions as needed
Project Setup
# Create a new Fly app
fly apps create warp-cluster
# Create volumes in each region
fly volumes create warp_data --region ams --size 10 # Amsterdam (EU)
fly volumes create warp_data --region iad --size 10 # Virginia (US)
fly volumes create warp_data --region sin --size 10 # Singapore (APAC)
# Deploy machines to each region
fly machine run . --region ams --volume warp_data:/data
fly machine run . --region iad --volume warp_data:/data
fly machine run . --region sin --volume warp_data:/data DNS Auto-Discovery
NewWarp nodes automatically discover each other via Fly's internal DNS. No manual seed configuration needed.
# fly.toml
app = "warp-cluster"
primary_region = "iad"
[env]
WARP_PORT = "9090"
WARP_DATA_DIR = "/data"
WARP_SHARDS = "16"
# Enable DNS-based cluster discovery
WARP_CLUSTER_DNS = "warp-cluster.internal"
[mounts]
source = "warp_data"
destination = "/data"
[[services]]
internal_port = 9090
protocol = "tcp"
[[services.ports]]
port = 9090
When WARP_CLUSTER_DNS is set, each Warp node queries Fly's internal DNS every 5 seconds
to discover other instances. New nodes are automatically added to the cluster, and shards are rebalanced
across the ring using consistent hashing. No manual intervention required.
Using the SDK
With DNS clustering, just use Warp.open() — nodes discover each other automatically.
import { Warp } from '@geeksquad/warp'
// Open spawns an embedded Warp server that auto-clusters via DNS
// WARP_CLUSTER_DNS is picked up from the environment (fly.toml)
const warp = await Warp.open({
dataDir: '/data', // Fly volume mount point
})
// That's it! The server joins the cluster automatically.
// Entity IDs with region prefixes route to the correct node.
// Create EU user → data stays in Amsterdam
const entity = warp.entity('eu/user/hans')
await entity.append('UserCreated', {
name: 'Hans Schmidt',
email: 'hans@example.de',
})
// Credit the account
await entity.append('Credited', { amount: 1000 })
// Read state
const state = await entity.get()
// Clean shutdown
await warp.close()
Requests are routed based on entity ID prefix. eu/user/hans routes to Amsterdam,
us/user/alice routes to Virginia. The cluster handles this transparently via
consistent hashing — you just use the entity ID and Warp figures out where to send it.
Scaling Up
Add more machines and shards rebalance automatically. No code changes needed.
# Scale up — add another machine in each region
fly machine run . --region ams --volume warp_data:/data
fly machine run . --region iad --volume warp_data:/data
# The new machines:
# 1. Query DNS and discover existing nodes
# 2. Join the cluster automatically
# 3. Receive shards via live rebalancing
# 4. Start serving traffic immediately
# Scale down — remove a machine
fly machine stop <machine-id>
# Remaining nodes detect the departure and
# redistribute shards among themselves High Availability
NewDeploy multiple machines per region for automatic failover. Replicas sync asynchronously with zero latency impact.
# Deploy 2 machines per region for HA (leader + replica)
fly scale count 2 --region ams
fly scale count 2 --region iad
fly scale count 2 --region sin
# Or deploy 3 for quorum-based leader election
fly scale count 3 --region ams
# Enable HA in fly.toml
[env]
WARP_HA_MODE = "replicated"
WARP_HA_REPLICAS = "2" Leader election: Highest sequence number wins. If tied, lowest node name wins (deterministic).
Replication: Fire-and-forget via BEAM's pg — no acks, no latency impact.
Failover: Replicas detect leader death, run election, winner takes over instantly.
GDPR Compliance
const entity = warp.entity(entityId)
const events = await entity.export()
// Returns all events for this entity const entity = warp.entity(entityId)
await entity.delete()
// Permanently removes entity and data function getDataResidencyInfo(entityId: string) {
const region = entityId.split('/')[0]
const info = {
eu: { datacenter: 'Amsterdam, Netherlands', jurisdiction: 'GDPR' },
us: { datacenter: 'Virginia, USA', jurisdiction: 'US Law' },
apac: { datacenter: 'Singapore', jurisdiction: 'PDPA' },
}
return info[region]
} Health Monitoring
import { Warp } from '@geeksquad/warp'
const warp = await Warp.open({ dataDir: '/data' })
// Check local node health
const health = await warp.health()
console.log(health)
// {
// overall: 'healthy',
// cluster: { nodes: 3, shards: 16 },
// local: { shards: 6, events: 142857 }
// }
// List all nodes in the cluster
const nodes = await warp.clusterNodes()
// ['warp@fdaa:0:1:a7b:...:2', 'warp@fdaa:0:2:...:2', ...] Summary
| Feature | Implementation |
|---|---|
| Clustering | WARP_CLUSTER_DNS env var (auto-discovery) |
| Data Residency | eu/, us/, apac/ entity ID prefix |
| Scaling | Add machines → shards rebalance automatically |
| High Availability | WARP_HA_MODE=replicated with automatic failover |
| Leader Election | Highest sequence wins, lowest node name tie-breaker |
| Replication | Fire-and-forget via BEAM pg (no latency impact) |
| Storage | Per-region Fly Volumes |
| GDPR Export | entity.export() |
| GDPR Delete | entity.delete() |
| Cross-region Queries | queryRegion() per region |