Deploy Dart & Dart Frog to Europe — EU Hosting for Flutter Backends in 2026
Flutter engineers have been writing Dart for years. The language is fast, null-safe, and backed by Google's long-term investment in cross-platform development. What fewer Flutter developers realise is that Dart is also a capable backend language — and Dart Frog, the server-side framework by Very Good Ventures, makes building production APIs in Dart surprisingly straightforward.
The appeal is the same as Swift for iOS teams or Kotlin for Android developers: one language across the entire stack. Define a User model once, use it in your Flutter app and your Dart Frog API. No JSON schema drift, no separate TypeScript or Go layer, the same null-safety guarantees on client and server.
This guide shows how to deploy a Dart Frog application to European infrastructure using sota.io, with EU data residency by default.
Why Flutter Teams Are Moving to Dart Frog
Flutter's growth has created a large pool of Dart developers who are comfortable with the language but often reach for Node.js or Python when they need a backend. Dart Frog changes that calculus:
Shared domain models. A User class defined in a shared Dart package works identically in Flutter and Dart Frog. The json_serializable annotations, the null-safety contracts, the copyWith methods — all shared. No manual synchronisation between client and server types.
Same async model. Dart's async/await and Stream system works identically in Flutter and on the server. A Flutter engineer who writes StreamBuilder widgets already understands how to write streaming route handlers in Dart Frog.
AOT compilation to native binaries. Dart compiles ahead-of-time to native machine code via dart compile exe. The resulting binary requires no Dart SDK at runtime — startup in under 100ms, memory footprint comparable to Go. No JVM, no Node.js process, no interpreter.
GDPR by design. Flutter teams building apps for European users — healthcare, fintech, consumer apps — often need their API in the EU. When the backend runs in Dart Frog on sota.io, EU data residency is the default, not a configuration step.
Dart Frog vs the Alternatives
Dart's server-side ecosystem has matured around a few options:
Dart Frog (Very Good Ventures) is the production-ready choice. File-based routing, middleware, dependency injection, and first-class support for hot reload during development. It handles the boilerplate so you write application code, not framework plumbing.
Shelf is the lower-level HTTP library that Dart Frog builds on. It is well-maintained but requires more manual setup. Worth it for microservices where you want minimal overhead.
Serverpod is a full-stack framework that generates client code for Flutter apps. Powerful, but opinionated — works best when you adopt it from the start of a project.
For Flutter teams adding a first backend, Dart Frog is the right starting point. It provides familiar patterns (file-based routing, like Next.js) without locking you into a specific architectural style.
What You Need
- Dart Frog application (Dart SDK 3.0+)
pubspec.yamlwithdart_frogdependency- A
Dockerfile(we will write one below)
Step 1: Create a Dart Frog Application
dart pub global activate dart_frog_cli
dart_frog create my_api
cd my_api
dart_frog dev
The project structure uses file-based routing — routes/users.dart handles GET /users and POST /users automatically. No configuration required.
A minimal route handler:
// routes/index.dart
import 'package:dart_frog/dart_frog.dart';
Response onRequest(RequestContext context) {
return Response.json(body: {'status': 'ok'});
}
For async handlers:
// routes/users/[id].dart
import 'package:dart_frog/dart_frog.dart';
Future<Response> onRequest(RequestContext context, String id) async {
final db = context.read<Database>();
final user = await db.findUser(id);
if (user == null) {
return Response(statusCode: 404);
}
return Response.json(body: user.toJson());
}
Step 2: Write a Production Dockerfile
Dart Frog supports AOT compilation — the production build compiles to a self-contained native binary. The resulting Docker image is small:
# Build stage — Dart SDK for compilation
FROM dart:stable AS build
WORKDIR /app
# Install Dart Frog CLI
RUN dart pub global activate dart_frog_cli
# Resolve dependencies
COPY pubspec.yaml pubspec.lock ./
RUN dart pub get
# Copy source
COPY . .
# Build production AOT binary
RUN dart_frog build
RUN dart compile exe build/bin/server.dart -o build/bin/server
# Runtime stage — just the binary, no Dart SDK needed
FROM debian:bookworm-slim
WORKDIR /app
# Required system libraries
RUN apt-get update && apt-get install -y \
libssl3 \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=build /app/build/bin/server ./server
EXPOSE 8080
ENTRYPOINT ["./server"]
The runtime image is typically 60–100 MB. The Dart SDK (~300 MB) stays in the build stage only. The compiled binary links against OpenSSL from the system packages.
Step 3: Configure Port and Database
Dart Frog reads environment variables via Platform.environment. sota.io injects PORT at runtime:
// build/bin/server.dart (generated)
// Override port via environment — modify in main.dart
import 'dart:io';
import 'package:dart_frog/dart_frog.dart';
void main() async {
final port = int.tryParse(Platform.environment['PORT'] ?? '') ?? 8080;
final server = await serve(createApp(), InternetAddress.anyIPv4, port);
print('Server running on port ${server.port}');
}
PostgreSQL via the postgres Package
When you attach a managed PostgreSQL instance in sota.io, the DATABASE_URL environment variable is injected automatically. Use the postgres package:
# pubspec.yaml
dependencies:
dart_frog: ^1.2.0
postgres: ^3.3.0
Create a database provider as Dart Frog middleware:
// routes/_middleware.dart
import 'dart:io';
import 'package:dart_frog/dart_frog.dart';
import 'package:postgres/postgres.dart';
Handler middleware(Handler handler) {
return handler.use(
provider<Connection>(
(context) => throw StateError('use _inject middleware'),
dispose: (connection) => connection.close(),
),
);
}
// lib/database.dart — initialise once at startup
Future<Connection> createConnection() async {
final uri = Platform.environment['DATABASE_URL']!;
return await Connection.open(
Endpoint.parse(Uri.parse(uri)),
settings: const ConnectionSettings(sslMode: SslMode.require),
);
}
Using the connection in a route:
// routes/users/[id].dart
import 'package:dart_frog/dart_frog.dart';
import 'package:postgres/postgres.dart';
Future<Response> onRequest(RequestContext context, String id) async {
final db = context.read<Connection>();
final result = await db.execute(
Sql.named('SELECT id, email, created_at FROM users WHERE id = @id'),
parameters: {'id': id},
);
if (result.isEmpty) {
return Response(statusCode: 404);
}
final row = result.first;
return Response.json(body: {
'id': row[0],
'email': row[1],
'created_at': (row[2] as DateTime).toIso8601String(),
});
}
Step 4: Deploy to sota.io
npm install -g @sota-io/cli
sota deploy
The CLI packages your Dockerfile, builds the Dart binary on sota.io infrastructure, and returns a live HTTPS URL. First builds take 2–4 minutes — Dart AOT compilation is fast compared to JVM or Rust. Subsequent deploys use cached pub get layers.
For automatic deploys on git push, connect your GitHub repository in the sota.io dashboard.
Performance: Dart vs Other Flutter-Adjacent Backends
Dart's AOT compilation to native machine code gives it structural performance advantages over interpreted and JVM runtimes:
| Runtime | Cold Start | Memory (idle) | Throughput |
|---|---|---|---|
| Dart / Dart Frog | ~80ms | ~25 MB | Very high |
| Go / Gin | ~20ms | ~15 MB | Very high |
| Swift / Vapor 4 | ~50ms | ~20 MB | Very high |
| Kotlin / Ktor | ~400ms | ~100 MB | High |
| Node.js / Fastify | ~100ms | ~50 MB | High |
| Python / FastAPI | ~300ms | ~80 MB | Moderate |
Dart is not the fastest runtime — Go and Swift edge it out on raw throughput — but it is significantly faster than Node.js and the JVM at startup and memory usage. For Flutter teams, the operational simplicity of one language across the full stack often outweighs a theoretical throughput advantage in a different language.
Comparison: sota.io vs Other Platforms for Dart Backend
| Feature | sota.io | Heroku | Railway | Fly.io |
|---|---|---|---|---|
| Default region | Germany (EU) | US default | US default | Configurable |
| EU data residency | Yes | Needs config | Paid plan | Yes (select regions) |
| GDPR EU DPA | Yes (EU entity) | No (Salesforce/US) | No (US entity) | Limited |
| Dart/Dart Frog support | Yes (Docker) | Yes (Buildpacks) | Yes (Docker) | Yes (Docker) |
| Managed PostgreSQL | Included | Paid add-on | Paid add-on | Separate |
| Pricing | Flat €9/mo | Usage-based | Usage-based USD | Usage-based USD |
| Cold starts | None | Free tier sleeps | None | None |
Honest comparison: Fly.io offers excellent global edge distribution and Docker-native support. sota.io wins when your requirement is EU data residency with an EU-entity DPA — the legal document required for GDPR Article 28 compliance when processing personal data of EU residents.
DACH Verticals for Dart/Flutter Backends
Dart Frog has natural traction in specific EU market segments where Flutter is already established:
Consumer apps (DACH). Flutter dominates cross-platform mobile development in the German-speaking market. Teams building for iOS and Android simultaneously often want their API in Dart too — one language, no context switching. sota.io's flat €9/month pricing fits pre-revenue Flutter startups.
Healthcare apps (DiGA, Switzerland). Germany's Digital Health Applications (DiGA) framework and Swiss healthcare data protection requirements mandate EU data processing. Flutter teams building health apps need their Dart Frog backend on EU infrastructure to satisfy both regulatory frameworks.
Fintech (Austria/Germany). Flutter's popularity in Austrian and German fintech startups — where BaFin and FMA oversight requires EU data processing — makes Dart Frog a natural backend choice. Type-safe database queries and compile-time null-safety reduce the risk of data-handling bugs in financial contexts.
EdTech platforms. Several DACH education platforms have adopted Flutter for cross-platform delivery. Dart Frog enables the backend team to share data models with the mobile team without a separate microservice for type translation.
Shared Types: The Flutter Full-Stack Advantage
The most compelling case for Dart Frog is not performance — it is shared code. Create a shared Dart package used by both your Flutter app and your Dart Frog backend:
packages/
shared/
lib/
src/
user.dart
product.dart
flutter_app/ # imports shared
dart_frog_api/ # imports shared
Your User model with json_serializable:
// packages/shared/lib/src/user.dart
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class User {
const User({required this.id, required this.email, required this.createdAt});
final String id;
final String email;
final DateTime createdAt;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
This model is used in Flutter's http calls and in Dart Frog's route handlers. Type errors caught at compile time, not at runtime in production.
What sota.io Gives You
- EU by default — Hetzner Germany, no configuration
- Automatic TLS — Let's Encrypt certificates, auto-renewed
- Managed PostgreSQL 17 —
DATABASE_URLinjected automatically - Flat pricing — €9/month, 2 GB RAM, 50 GB storage, no egress fees
- Native binary performance — Dart AOT, no VM overhead
npm install -g @sota-io/cli
sota auth login
sota deploy
Your Dart Frog API is live in Germany.
See also: Deploy Swift & Vapor to Europe · Deploy Kotlin & Ktor to Europe · All Languages to Europe