How to build a server in Dart: CTO insights
Learn how to build a server in Dart with expert insights from a CTO. Discover step-by-step guidance to create efficient and scalable servers using Dart.
A bit about me before we dive in. I am CTO at Pieces for Developers, and I have been in software for roughly 10 years now working mainly on backend + cloud infrastructure everything from (local/cloud server, and database infrastructure, and generally anything and everything to do with Backend development).
Throughout this tutorial series I will be referencing Pieces for Developers, our main goal is building long-term memory for developers intractable via a Conversation form factor using the cloud LLM of your choosing.
Using Pieces is not required for this tutorial series, however, if you want to further your development skills, and reduce context switching while using the power of Long Term Memory then I would recommend taking a look at Pieces for Developers and our lengthy list of products.
Getting started
Have you ever wondered how services like Stripe, SendGrid, and many others implement their backend? If so, this is the right article for you!
One of the key components of a backend is rest API and, specifically an HTTP (or RPC) server that will accept these requests.
Today, we will build a local HTTP server using pure Dart and an awesome Dart package called Shelf Plus. We will set up our project, set up our server, and add a single health check route. There are plenty more topics to dive into, like middleware, streaming, persistence, automated testing, and much more, but we’ll save these topics for future blog posts!
Step 1: Create a new repository
Let’s start by creating a brand new repository written in Dart. For this, ensure that you have Flutter installed, open up your favorite IDE (I prefer IntelliJ) in a brand new directory, and we are ready to Rock🤘
Create your first file, pubspec.yaml. Let’s add the following code to the pubspec.yaml file:
As you see, we have a pretty empty pubspec with just a few things to note.
First, our environment will need to encapsulate your specific version of Dart.
For instance, I am on Dart version 3.4.4, and this version will fall within the bounds of our version here. Secondly, a lot goes into building a server from scratch, like request routing and handling, concurrency and long-running tasks, port binding, and server management–just to name a few.
To keep things straightforward, let's skip over these parts and use an awesome package(shelf_plus), so we can jump into the fun stuff. If you want to learn a little more about packages in Dart here is a great article. This gives us the ability to have a long-running HTTP server that serves a specified port with a series of specified routes.
Step 2: Set up your project structure
Run a `Flutter pub get` in our project to get all of our dependencies.
Create a ‘lib’ folder with 2 files, a main.dart and a file called initialize_routes.dart.
Our project should look a little like the Figure below (without the .idea folder, most likely).

Next, let's boot up our server and add our first route (our health check). For this, let’s start with our main.dart file, which is the entry point to any Flutter/Dart project. Then, let’s add the following code:
As we can see here, we will have two imports ShelfPlus ‘shelfRun’ this will start our server by providing a function that will initialize our routes. The shelfRun function enables us to configure a bunch of things, like a specified port, handling graceful shutdowns, and a bunch of other utilities that can be explored further here.
We are also importing a function called initializeRoutes from our local repository (currently, I have my import set to absolute paths, but can also use relative paths here ie `import ‘../initialize_routes.dart’;`). Note: ‘building_a_local_dart_server’ is the name of the current package within the pubspec.yaml.
This function, initializeRoutes, will define the set of routes that we will need to get our server fully functional–but let's start with the health check and verify everything is up and running.
This code will define a function called ‘initializeRoutes’ that will return a handler that will be provided to the server in the main.dart file.
In the function body, we will create a new instance of our Router, and we will define a GET request, at the route ‘’/.well-known/health”.
Next, we’ll pass in a function to our get request that will handle the request ie whenever someone makes a request to this endpoint we will run the following code. The code will accept a request, which is the request from the ‘client’ that makes a request to your server, we will print to the console saying that “well known” was called, then we will return a 200 status code with a body in the request just return a string of ‘ok’.
Step 3: Run and test your server
Now to ensure that everything is running properly, let's run our server and simulate a client-side request. To do this let's first navigate to our terminal or command line in the specified directory of the project, then run another `pub get` to ensure our packages are up to date, and run a `dart run` via the following commands.
After you run this you should see the following in your terminal:
Next, let's make our Request! Since we are just using a GET request, which requires no input in the request body, we can just navigate to your preferred browser and paste in the following URL:
If this works properly, you should see ‘ok’ on your browser window, and you should see “well-known called!” in your terminal. This means you have successfully built a local server in Dart
Here is a link to the repository & the Part 1 commit. In this article, we created our dart project, added our shelf_plus dependency, and initialized our project with 2 files–our main.dart which is the entry point, and our initialize_routes.dart file with just a single GET request. In the next article, we’ll add GET, POST, and DELETE requests to showcase all our CRUD operations, as well as automated tests to ensure that everything is running properly.
If you liked this article, you might find the other ones useful too:
