Server-Side Dart
Prerequisites: Futures and async/await, Working with JSON
Dart also runs on servers. Its async I/O handles many connections efficiently, it compiles to a small native executable, and a Flutter team can share model classes and validation between app and back end.
A JSON API with Shelf
Shelf is the Dart team's composable web server library:
dart create -t server-shelf todo_api
import 'dart:convert';
import 'dart:io';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_router/shelf_router.dart';
final _tasks = <Map<String, Object?>>[];
var _nextId = 1;
Response _json(Object? body, {int status = 200}) => Response(
status,
body: jsonEncode(body),
headers: {'content-type': 'application/json'},
);
Future<void> main() async {
final router = Router()
..get('/health', (Request req) => _json({'status': 'ok'}))
..get('/tasks', (Request req) => _json(_tasks))
..post('/tasks', (Request req) async {
final body = jsonDecode(await req.readAsString());
if (body case {'title': String title} when title.trim().isNotEmpty) {
final task = {'id': _nextId++, 'title': title, 'done': false};
_tasks.add(task);
return _json(task, status: 201);
}
return _json({'error': 'title is required'}, status: 422);
});
final handler = const Pipeline().addMiddleware(logRequests()).addHandler(router.call);
final server = await io.serve(handler, InternetAddress.anyIPv4, 8080);
print('Listening on port ${server.port}');
}
$ curl -X POST localhost:8080/tasks -H "Content-Type: application/json" -d '{"title":"Learn Shelf"}'
{"id":1,"title":"Learn Shelf","done":false}
- A handler is simply a function from
RequesttoResponse. - Middleware (such as
logRequests) wraps handlers to add behavior to every request. - The
if-casepattern validates the JSON body's shape in one step.
Frameworks such as Dart Frog and Serverpod build on these ideas with file-based routing, code generation, and database integration.
Deployment
dart compile exe bin/server.dart -o build/server
The result is a single native executable with no Dart SDK needed at
runtime, making for small Docker images (the dart create template
includes a Dockerfile).
When to choose it
Server-side Dart makes most sense for Flutter teams who want one language across the stack. For a team starting fresh, larger back-end ecosystems (Go, Node.js, Python, Java, Kotlin) offer more libraries and hosting options.