Deploy Gleam to Europe — EU Hosting for Gleam & BEAM Applications in 2026
Gleam is a language with an unusual value proposition: the type safety of ML combined with the concurrency model of Erlang. It runs on the BEAM — the Erlang virtual machine that powers WhatsApp, Discord, and Klarna — but brings a modern, statically-typed syntax that eliminates an entire class of runtime errors the Erlang ecosystem has traditionally tolerated.
This combination matters in Europe. The BEAM has deep European roots: it was designed and built at Ericsson in Sweden in the 1980s to run telephone exchanges with nine-nines uptime (99.9999999%). Klarna, Europe's largest buy-now-pay-later fintech with millions of Swedish and EU customers, runs significant infrastructure on BEAM. The runtime's track record in regulated, high-reliability, EU-headquartered industries is unmatched.
Gleam is the first statically-typed language to target the BEAM natively. It also compiles to JavaScript, which means you can share types between your backend Gleam service and your frontend — without a separate schema definition step.
This guide shows how to deploy Gleam applications — using the Wisp web framework — to EU infrastructure with sota.io.
Why Gleam: Type Safety on the Most Reliable Runtime Ever Built
The BEAM's concurrency model is fundamentally different from threads (Java, Go, .NET) or async/await (Node.js, Python). Processes in BEAM are:
- Lightweight: A million BEAM processes use less memory than ten thousand OS threads.
- Isolated: Each process has its own heap. A crashed process does not corrupt shared state — it crashes independently, and a supervisor restarts it.
- Preemptively scheduled: The BEAM scheduler distributes processes across CPU cores without yielding calls in your code. There is no callback hell, no async-await boilerplate, no manual thread pool management.
This model originated from a hard requirement: Ericsson needed telephone exchange software that could restart a failed component without taking down a call in progress. The "let it crash" philosophy — handle errors at the supervision level, not defensively at every call site — is not a design pattern you bolt on. It is built into the runtime.
Erlang's weakness has always been its dynamic type system. Runtime type errors are logged, not caught at compile time. Dialyzer (Erlang's optional type checker) helps but is notoriously slow and imprecise. Elixir, the most popular BEAM language, inherits this limitation.
Gleam solves this. Its type system is complete and sound — if it compiles, it does not throw a runtime type error. The compiler gives you Elm-quality error messages and exhaustive pattern match checking. You get:
- No runtime type errors ever
- Exhaustive case expressions — every branch must be handled
- No
nil/null— useOption(t)explicitly - Friendly, actionable compiler messages (Gleam's compiler is famous for this)
- Full interop with Erlang and Elixir libraries (the BEAM ecosystem is enormous)
For backend services in fintech, healthcare, or any regulated EU domain, this combination is compelling: the reliability of a runtime with decades of nine-nines production history, plus compile-time type guarantees that eliminate a category of bugs Erlang teams currently catch in production.
Gleam's European Industry Context
Klarna (Stockholm). Europe's largest BNPL company processes billions of transactions annually on BEAM infrastructure. While Klarna uses Erlang and Elixir rather than Gleam, the runtime choice validates the reliability story for EU fintech. Teams at Klarna-adjacent EU fintech companies looking for a typed BEAM language have started evaluating Gleam as Erlang modernization.
Ericsson's ongoing investment. Ericsson maintains OTP — the Open Telecom Platform that is the core of the Erlang/BEAM ecosystem. Their 5G infrastructure and network management software continues to rely on BEAM, and they contribute upstream. Gleam interoperates with OTP fully: Gleam processes are OTP processes, Gleam supervisors are OTP supervisors.
Healthcare and telco in Germany, Austria, Switzerland. High-reliability requirements in DACH healthcare backends (patient data, appointment systems, medical device integration) and telco infrastructure (SIP proxy, billing systems) map directly to BEAM's concurrency model. These industries also have strict EU data residency requirements — Austrian KSA, Swiss DSG, German BDSG all require EU-jurisdiction processing.
Early-stage EU fintech teams. A cohort of European fintech startups building payment infrastructure, banking APIs, and financial data pipelines are choosing Gleam specifically for the combination of type safety and fault-tolerance. The language's growing ecosystem (Wisp for HTTP, Lustre for frontend, pog for PostgreSQL) now covers the standard backend stack.
What You Need
- Gleam 1.x (
gleam --version) - Erlang/OTP 26+ (installed via
asdfor system package manager) - Wisp + Mist for the HTTP layer
- A
Dockerfile
Gleam manages dependencies via gleam.toml and a lock file, similar to Cargo or mix.
Step 1: A Minimal Wisp Application
Wisp is Gleam's primary web framework. It has an intentionally small API — middleware composition, typed request/response handling, and clean routing.
Project structure:
my-gleam-api/
├── src/
│ ├── my_gleam_api.gleam
│ └── my_gleam_api/
│ ├── router.gleam
│ └── web.gleam
├── gleam.toml
└── manifest.toml
src/my_gleam_api.gleam:
import gleam/erlang/process
import mist
import wisp
import my_gleam_api/router
pub fn main() {
wisp.configure_logger()
let port = case wisp.get_env("PORT") {
Ok(p) -> { let assert Ok(n) = int.parse(p); n }
Error(_) -> 8080
}
let assert Ok(_) =
wisp.mist_handler(router.handle_request, _)
|> mist.new()
|> mist.port(port)
|> mist.start_http()
process.sleep_forever()
}
src/my_gleam_api/router.gleam:
import gleam/http.{Get}
import gleam/json
import wisp.{type Request, type Response}
pub fn handle_request(req: Request) -> Response {
case wisp.path_segments(req) {
["health"] -> health(req)
["api", "users", id] -> get_user(req, id)
_ -> wisp.not_found()
}
}
fn health(_req: Request) -> Response {
json.object([#("status", json.string("ok"))])
|> json.to_string_tree()
|> wisp.json_response(200)
}
fn get_user(req: Request, id: String) -> Response {
case req.method {
Get ->
json.object([#("id", json.string(id))])
|> json.to_string_tree()
|> wisp.json_response(200)
_ -> wisp.method_not_allowed([Get])
}
}
gleam.toml:
name = "my_gleam_api"
version = "1.0.0"
[dependencies]
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
gleam_erlang = ">= 0.25.0 and < 2.0.0"
gleam_http = ">= 3.6.0 and < 4.0.0"
wisp = ">= 0.13.0 and < 2.0.0"
mist = ">= 2.0.0 and < 3.0.0"
gleam_json = ">= 1.0.0 and < 2.0.0"
[dev-dependencies]
gleeunit = ">= 1.0.0 and < 2.0.0"
Step 2: Write a Production Dockerfile
Gleam compiles to Erlang source code, which is then compiled by the Erlang compiler. The multi-stage build keeps the final image small:
# Build stage — Gleam + Erlang/OTP
FROM ghcr.io/gleam-lang/gleam:v1.6.1-erlang-alpine AS build
WORKDIR /app
# Copy dependency manifests first for layer caching
COPY gleam.toml manifest.toml ./
RUN gleam deps download
# Copy source and build
COPY src/ ./src/
RUN gleam export erlang-shipment
# Runtime stage — Erlang OTP only (no Gleam toolchain needed)
FROM erlang:26-alpine
WORKDIR /app
COPY --from=build /app/build/erlang-shipment ./
EXPOSE 8080
ENTRYPOINT ["/app/entrypoint.sh", "run", "my_gleam_api"]
The Gleam build produces an "erlang-shipment" — a self-contained directory with compiled BEAM bytecode and an entrypoint.sh script. The runtime image needs only Erlang/OTP (no Gleam, no build tools). Final image size: typically 50–80 MB.
Note: gleam export erlang-shipment is the canonical way to package Gleam apps for production. It produces a standard OTP release structure that runs on any Erlang installation.
Step 3: Deploy to sota.io
# Install the sota CLI
npm install -g sota-cli
# Login
sota login
# Deploy — sota detects the Dockerfile automatically
sota deploy
Your Gleam service is live in Germany with automatic HTTPS. Scale is handled by sota.io's container infrastructure — no configuration needed for the standard Wisp/Mist setup.
Step 4: PostgreSQL with pog
pog is Gleam's PostgreSQL client. It provides a typed query interface and connection pooling over epgsql (the battle-tested Erlang PostgreSQL driver).
When you attach a managed PostgreSQL database in sota.io, DATABASE_URL is injected automatically.
import gleam/dynamic/decode
import gleam/option.{type Option}
import pog
pub type User {
User(id: Int, email: String)
}
fn user_decoder() -> decode.Decoder(User) {
use id <- decode.field(0, decode.int)
use email <- decode.field(1, decode.string)
decode.success(User(id:, email:))
}
pub fn find_user(db: pog.Connection, id: Int) -> Result(Option(User), pog.QueryError) {
pog.query("SELECT id, email FROM users WHERE id = $1")
|> pog.parameter(pog.int(id))
|> pog.returning(user_decoder())
|> pog.execute(db)
|> result.map(fn(response) {
case response.rows {
[user] -> option.Some(user)
_ -> option.None
}
})
}
Add pog to your gleam.toml dependencies:
pog = ">= 0.13.0 and < 2.0.0"
The type-safe decoder pattern means column count and type mismatches are caught at decode time, not silently swallowed. Combined with Gleam's Result type (no exceptions), you get explicit, composable error handling throughout the database layer.
Step 5: Configure sota.toml
[app]
name = "my-gleam-api"
region = "eu-central" # Frankfurt, Germany
[build]
dockerfile = "Dockerfile"
[env]
PORT = "8080"
# DATABASE_URL is injected automatically when you attach a PostgreSQL service
Performance: Gleam/BEAM vs Other Backends
BEAM performance characteristics are different from native-compiled languages. Raw throughput is modest; the value is latency stability under load and horizontal scaling without shared state:
| Runtime | Requests/sec (simple JSON) | Memory (baseline) | Latency p99 (under load) |
|---|---|---|---|
| Rust/Axum | ~95,000 | ~8 MB | ~1.2 ms |
| Go/Chi | ~82,000 | ~15 MB | ~1.8 ms |
| OCaml 5/Dream | ~68,000 | ~22 MB | ~2.1 ms |
| .NET/ASP.NET Core | ~65,000 | ~55 MB | ~2.4 ms |
| Gleam/Wisp (BEAM) | ~35,000 | ~35 MB | ~2.8 ms |
| Node.js/Express | ~32,000 | ~45 MB | ~4.8 ms |
| Python/FastAPI | ~10,000 | ~50 MB | ~8.5 ms |
Gleam's raw throughput is not the headline. The headline is the p99 under load: because BEAM processes are preemptively scheduled and isolated, latency distribution stays flat as concurrency increases. In thread-based runtimes (Java, .NET), p99 latency often spikes dramatically under connection surges. The BEAM does not. This is why Erlang is used for real-time communication (WhatsApp, Discord) where consistent latency matters more than peak throughput.
For payment APIs, healthcare appointment systems, and fintech backends where you cannot afford tail latency spikes during peak hours, this property is more valuable than raw RPS numbers.
EU Deployment: Compliance Requirements for BEAM Workloads
The industries that have historically chosen BEAM — fintech, telco, healthcare — are also the industries with the strictest EU data residency requirements.
GDPR Article 44 and Schrems II. US PaaS providers — AWS, GCP, Azure, Vercel, Railway, Render — are subject to the US Cloud Act regardless of where they locate your data. A US government request can compel disclosure of data stored on a US company's servers in Frankfurt. For EU-regulated entities (banks under PSD2, healthcare providers under national health data laws, companies handling personal data at scale), this is a material compliance risk.
PSD2 and financial data. EU payment service providers handling transaction data must demonstrate data sovereignty. German BaFin, Austrian FMA, and French ACPR have all issued guidance that Cloud Act-exposed providers create compliance gaps. BEAM-based payment backends running on sota.io — German-incorporated, Hetzner Frankfurt infrastructure — close this gap cleanly.
Klarna-style fintech infrastructure. European BNPL, neobank, and payment infrastructure companies building on BEAM need a deployment target that matches their compliance posture. sota.io is the only PaaS that covers both the technical requirement (OTP/BEAM support) and the legal requirement (EU entity, no Cloud Act) in one product.
sota.io vs the Alternatives for Gleam/BEAM
| Feature | sota.io | Fly.io | Railway | Render | Heroku |
|---|---|---|---|---|---|
| EU data residency (default) | Yes — Germany | Partial | No | No | No |
| German legal entity | Yes | No | No | No | No |
| US Cloud Act exposure | None | Yes | Yes | Yes | Yes |
| Managed PostgreSQL | Yes | Add-on | Add-on | Add-on | Add-on |
| BEAM/OTP Docker support | Full | Full | Full | Full | Limited |
| Flat-rate pricing | Yes | Usage-based | Usage-based | Usage-based | Usage-based |
| DPA (GDPR Article 28) | Yes | Limited | No | Limited | Limited |
Fly.io has good Docker support and EU machine options, but is incorporated in the US. For Gleam teams in regulated EU fintech or healthcare, Cloud Act exposure is a hard blocker. Railway and Render have no EU-native story at all.
DACH and EU Verticals for Gleam
EU Fintech (DE/AT/CH). Payment API backends, banking integrations, and ledger systems are natural fits for BEAM's fault-tolerance model. German N26, Austrian George by Erste Group, and Swiss fintech teams at Zurich cantonal banks have evaluated Erlang/Elixir — Gleam offers the same runtime with modern type safety.
Telco and Network Infrastructure. Ericsson's BEAM heritage means telco infrastructure teams in Germany, Sweden, and the Netherlands are the most BEAM-experienced anywhere. Gleam is gaining traction for new service components — SIP proxies, signaling servers, billing APIs — where OTP supervision trees are required but Erlang's lack of types is a maintenance problem.
Healthcare Backends (DACH). German healthcare interoperability mandates (HL7 FHIR, gematik TI) require both reliability and compliance. Gleam backends serving health data APIs combine OTP's nine-nines reliability with type-safe data handling and EU-only data residency.
Getting Started
# Install Gleam (macOS/Linux)
# See https://gleam.run/getting-started/installing/
# Install Erlang/OTP 26+ (macOS via Homebrew)
brew install erlang
# Create a new project
gleam new my-gleam-api
cd my-gleam-api
# Add Wisp
gleam add wisp mist gleam_json
# Run locally
gleam run
# Build and deploy to EU
sota deploy
Your Gleam backend is live in Germany — BEAM reliability, compile-time type safety, and GDPR-compliant EU data residency in one deployment.
The BEAM was built to keep telephone calls alive when hardware fails. Your API deserves the same guarantee.
Deploy your Gleam application to EU infrastructure today — sign up for early access or run sota deploy if you already have an account.