top of page

Dart in Backend Development

  • Writer: Maksim Murin
    Maksim Murin
  • May 29
  • 5 min read

Updated: 9 minutes ago

When most developers think of Dart, they often associate it with Flutter and building beautiful UIs for mobile and web 📱💻. However, Dart is also a powerful language for backend development — clean, fast , and easy to get started with⚡.

In this article, we'll explore Dart on the server side by building a simple RESTful API using the lightweight shelf package 📦. No databases, no frameworks — just core Dart and a few essential packages to demonstrate how straightforward backend development can be 🛠️.



This project is also connected to our earlier articles about a Game development on MAUI 🎮. The idea is to use this backend as a way to store scores from that game — adding a real-world, practical touch with our example. It’s not just a demo, it’s a small piece of a bigger puzzle🧩.


game scores screen

In this article, we’ll create a lightweight REST API using Dart’s shelf package. The app will let us submit, list, and delete scores, storing them in memory. It's a perfect minimal backend — simple, fast, and focused on demonstrating Dart's capabilities on the server side.


No heavy frameworks. Just pure Dart, a few libraries, and clean design.


🚀 Why Use Dart in Backend?

When you think of backend development, Dart might not be the first language that comes to mind — but that’s changing fast. Dart is no longer just a language for Flutter apps. It's quietly growing into a capable, efficient, and developer-friendly option for building fast and modern backend services.

Here’s why Dart truly shines on the server side:


Lightning-Fast and Native-Ready

Dart compiles to highly optimized native machine code, making it incredibly fast for backend use. Whether it’s parsing JSON, handling concurrent requests, or serving static content, Dart performs consistently well — and doesn’t require a massive runtime or VM to get started.

Thanks to its event-driven, asynchronous model, Dart is excellent at handling many simultaneous connections — making it perfect for real-time games, chat apps, and APIs.


🔄 One Language to Rule Them All

One of Dart’s superpowers is that it enables full-stack development with a single language. You can build beautiful Flutter apps for mobile, web, and desktop — and then use the same language to power your backend API.


🧱 Minimal Yet Modular with Shelf

Dart doesn’t force you into a massive framework with opinions about everything. Instead, it gives you tools like Shelf — a flexible, middleware-based HTTP server library.


📦 Modern Ecosystem, Friendly Tooling

Dart has come a long way, with an ecosystem that now supports:

  • HTTP clients and servers.

  • PostgreSQL, MySQL, and NoSQL database drivers.

  • JWT authentication and encryption tools.

  • Dependency injection, testing libraries, and more.

And don’t forget the tooling: Dart’s built-in formatter, analyzer, and testing support are a joy to use. Plus, hot reload works in many backend workflows — just like in Flutter.


In short, Dart is an underrated gem in backend development. It offers the speed of Go, the asynchronicity of Node.js, and the developer experience of modern languages like Kotlin or Swift — all wrapped in one sleek package.


Implementing server in dart

Although our demo app is intentionally simple, it highlights several powerful capabilities of Dart and the shelf ecosystem. To better understand how this backend fits into the bigger picture, here’s a simple flowchart that shows the basic data flow:

backend flowchart

Here’s a breakdown of the key features we implemented to show what Dart can do on the server:


1️⃣ A Quick Word About Shelf

Before we dive into implementation, meet Shelf — the lightweight, composable web server framework for Dart. Inspired by concepts from middleware-based frameworks, Shelf gives you full control over HTTP requests and responses without unnecessary abstractions.

It’s minimal, but not limiting. Shelf lets you build web servers, APIs, and even microservices with clear routing, layered middleware, and a functional programming style — all perfectly suited for Dart’s expressive syntax. It’s the go-to choice when you want to showcase Dart’s server-side capabilities without reaching for heavy frameworks.


Preparatory to creating our Dart server, we need to add a few essential dependencies to our pubspec.yaml file.

  • shelf – the core web server framework,

  • shelf_router – for clean and simple route definitions,

  • uuid – to generate unique identifiers for our data.


2️⃣ Core Server Configuration

At the heart of our backend lies a compact yet powerful server setup. It demonstrates how Dart’s shelf ecosystem allows you to build structured, extensible web servers with minimal boilerplate.


We begin by creating a Router instance, which acts as our central routing table. This is where we register route handlers — in this case, we mount our ScoreHandler under the /scores/ path:

router.mount('/scores/', scoreHandler.router.call)

Dart's shelf allows stacking middleware in a pipeline-style configuration. We use this to add essential functionality to every request:

  • logRequests() – Logs each HTTP request with method and path info. Handy for debugging and visibility during development.

  • jsonContentTypeMiddleware() – A custom middleware that automatically sets the Content-Type header to application/json for all responses.


These middlewares are composed into a final handler:


final handler = Pipeline()
    .addMiddleware(logRequests())
    .addMiddleware(jsonContentTypeMiddleware())
    .addHandler(router.call);

The server is launched using shelf_io.serve, which listens on port 8080 and binds to all IPv4 interfaces (so it’s accessible from other devices on your network):


final server = await shelf_io.serve(
  handler,
  InternetAddress.anyIPv4,
  8080,
);

Using Shelf’s Router, Dart allows you to set up REST-style endpoints in a highly readable and scalable way. Each route can be tied to a function that handles a specific HTTP method:


 ScoreHandler() : router = Router() { 
    /// GET /scores/ 
    router.get('/', _getAllScores); 
    /// POST /scores/ 
    router.post('/', _addScore); 
 
    /// DELETE /scores/id 
    router.delete('/<id>', _deleteScore); 
  } 
 
  // Handler for GET /scores/ 
  Future<Response> _getAllScores(Request request) async { 
    final queryParams = request.url.queryParameters; 
 
    int? minScore; 
    if (queryParams.containsKey('min')) { 
      minScore = int.tryParse(queryParams['min'] ?? '0'); 
    } 
 
    final scores = _storage.getAllScores(); 
 
    final filtered = minScore != null ? scores.where((s) => s.score >=
(minScore ?? 0)).toList() : scores; 
 
    final json = jsonEncode(filtered.map((s) => s.toJson()).toList()); 

    return Response.ok(json); 
  }

This approach makes it easy to grow your backend while keeping your logic modular and clear.


3️⃣ How We Tested the Backend

To simulate real client requests, we used curl, a lightweight command-line tool available on most systems. For example:

  • Add a score:

curl -X POST http://localhost:8080/scores/ -H "Content-Type: application/json" -d "{\"score\": 120}"
  • Get all scores:

curl http://localhost:8080/scores/
  • Filter scores by minimum value:

curl http://localhost:8080/scores/?min=100
  • Delete a score by ID:

curl -X DELETE http://localhost:8080/scores/<score-id>

With the core logic in place and our server properly configured using Shelf's elegant routing and middleware system, the next step was to ensure everything worked as expected.


server in work example

Conclusion

Dart has long been recognized for its power and simplicity in frontend development with Flutter, but as this article demonstrates, its capabilities go far beyond the UI. By leveraging the lightweight and flexible Shelf package, we built a simple yet effective backend to store and retrieve game scores — showcasing Dart’s ability to handle routing, middleware, and JSON APIs with ease.


come to the dart side

This project not only extends our existing game-related work, but also proves how a single language can now cover both client and 🖧server sides, making development faster and more cohesive. If you're already using Dart for frontend, trying it on the backend may be your next natural — and surprisingly powerful step.

📂 Full project source code is available below.


Let’s Build the Future Together

At Igniscor, we don’t just develop apps — we create full-stack digital experiences. From embedded systems and powerful backend architectures to sleek, user-friendly mobile interfaces, we bring your ideas to life with precision and passion. Have a project in mind? Let’s make it happen — contact us today.



Comments


Recent Posts

Leave us a message and we'll get back to you

Our Location

Warszawska 6, lok. 32

Bialystok, Poland

Message was sent! Thanks

bottom of page