Deployment Guides

Deploy
Anywhere

Production-ready deployment patterns for Warp. Multi-region, GDPR-compliant, and battle-tested.

Fly.io with GDPR Data Residency

Featured

Deploy 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.

Multi-region GDPR DNS Clustering High Availability Volumes

Docker Compose

Coming Soon

Local development and single-node production deployments with Docker Compose.

Kubernetes

Coming Soon

StatefulSets, persistent volumes, and horizontal scaling on Kubernetes.

Railway

Coming Soon

One-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)     │
     └─────────────┘    └─────────────┘    └─────────────┘
Key Principles
  • 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
High Availability
  • Leader writes, replicas sync async
  • Fire-and-forget (no latency impact)
  • Automatic failover on leader death
  • Highest sequence wins election
Benefits
  • GDPR compliant data residency
  • Zero data loss on failover
  • Easy export and deletion per entity
  • Add more regions as needed
01

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
01.5

DNS Auto-Discovery

New

Warp 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
How it works

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.

02

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()
How routing works

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.

03

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
03.5

High Availability

New

Deploy 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"
How HA works

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.

04

GDPR Compliance

Right to Access (Export)
const entity = warp.entity(entityId)
const events = await entity.export()
// Returns all events for this entity
Right to Erasure (Delete)
const entity = warp.entity(entityId)
await entity.delete()
// Permanently removes entity and data
Data Residency Proof
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]
}
05

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