Build and deploy a Dart server using Alfred, Docker and Google Cloud Run from start to finish.

Ryan Knell
4 min readMay 20, 2021

--

Well its official — Google just released properly supported docker images focusing on Dart on the server as part of their Dart 2.13 release.

If you are writing Flutter apps and love Dart, there is no reason not to write your backend in Dart too!

Let's build a quick Alfred server, containerize it and then publish using Google cloud run. I estimate it will take a novice about 30 minutes, and with experience should take no more than 10.

This assumes you have the Dart SDK already installed on your machine.

Step 1. Building a quick app with Alfred.

Create a new folder called alfred-hello-world and place the following pubspec.yaml file inside:

name: alfred_hello_world

publish_to: none #dont publish to pub.dev
description: Hello world Alfred server

environment:
sdk: ">=2.12.0 <3.0.0"

dependencies:
alfred:

Then run

pub get

Next, create the file bin/server.dartit is vitally important you name it this for the later step.

In that file write the following code:

import 'dart:io';

import 'package:alfred/alfred.dart';

void main() async {
final app = Alfred();

app.get('/helloworld', (req, res) => "Hello world!");

app.get(
'/totallynotarickroll',
(req, res) => res
.redirect(Uri.parse('https://www.youtube.com/watch?v=dQw4w9WgXcQ')));

final envPort = Platform.environment['PORT'];

final server = await app.listen(envPort != null ? int.parse(envPort) : 8080);

print("Listening on ${server.port}");
}

In this file, what it's doing is pretty straightforward. Its creating a server instance, then creating a route /helloworld. When the user hits the helloworld route, return the text “Hello World”. Alfred is pretty smart, if you want to return a file or JSON, it will handle that too. But to get started we are just returning plain old text.

That’s it! You have just created a simple server. Let’s test it out!

dart bin/server.dart

It should print:

Listening on 8080

and when you go to http://localhost:8080/helloworld you should see “Hello world!”

Tip: for extra credit you can run dart compile exe bin/server.dart -o bin/server on mac or dart compile exe bin\server.dart -o server.exe on windows and it will create a fully self contained binary you can give to your friends to show off your skills. This bit is going to be done by the Docker container in the next step for you.

Phew! Now on to the slightly trickier part.

Step 2. Containerizing your dart server

First, you need to install Docker if you haven’t already.

Docker is going to build your app into a container with a minimal OS ready to run your server on any platform. Once its all bundled up we are going to host it.

With docker installed create two files in your project’s root directory. Just straight up copy and paste these, nothing to edit. The code for them is taken from the official dart docker instructions here. The Dockerfile contains all the commands to build your server using ahead of time (AOT) compilation so its lightning fast. You may also notice why it's important to name your file bin/server.dart if you dig in.

/Dockerfile

# Specify the Dart SDK base image version using dart:<version> (ex: dart:2.12)
FROM dart:stable AS build

# Resolve app dependencies.
WORKDIR /app
COPY pubspec.* ./
RUN dart pub get

# Copy app source code and AOT compile it.
COPY . .
# Ensure packages are still up-to-date if anything has changed
RUN dart pub get --offline
RUN dart compile exe bin/server.dart -o bin/server

# Build minimal serving image from AOT-compiled `/server` and required system
# libraries and configuration files stored in `/runtime/` from the build stage.
FROM scratch
COPY --from=build /runtime/ /
COPY --from=build /app/bin/server /app/bin/

# Start server.
EXPOSE 8080
CMD ["/app/bin/server"]

/.dockerignore

.dockerignore
Dockerfile
build/
.dart_tool/
.git/
.github/
.gitignore
.packages

Cool beans!

With that created you can now bundle your project up. First build it and then run it:

docker build -t dart-server . docker run -it --rm -p 8080:8080 --name myserver dart-server

Now you can navigate as you did before to http://localhost:8080/helloworld and it should all be working.

If you are done run docker kill myserver to clean up.

Step 3. Deploying to Google Cloud Run

We are using Google Cloud Run as an example, but this could just as easily be Heroku or any other service that takes a docker image.

This section is a streamlined version of the instructions found here.

  1. Install the gcloud sdk on your machine.

2. Go to the Google Cloud Console API and create a project: https://console.cloud.google.com/projectselector2/home/dashboard

Note the project id, something like alfred–314312

Upon retrying this tutorial on a fresh project I also needed to enable the cloud run api, even though the current gcloud tool suggested it was setting it up for me. I expect this will be resolved in the future. The link for the cloud run api is here: https://console.cloud.google.com/marketplace/product/google/run.googleapis.com

3. You will need to enable billing.

Once the boring admin stuff is done, return to the command line and run the following in your project directory:

gcloud auth login

Once authenticated, run, putting the project ID you noted above where is says [PROECT_ID]:

gcloud beta run deploy alfred-hello-world --source . --allow-unauthenticated --project=[PROJECT_ID]

What the command is saying is — grab the Dockerfile and build it, upload it to the project, create an instance called ‘alfred-hello-world’, and allow the public to access your server. It will prompt you as to where you want to store it. The signature for the command is below so you can save it for future use:

gcloud beta run deploy NAME \
--source=PATH \ # can use $PWD or . for current dir
--project=PROJECT \ # the Google Cloud project ID
--region=REGION \ # ex: us-central1
--platform=managed \ # for Cloud Run
--allow-unauthenticated # for public access

Boom!

… actually it takes a minute or two. But then

Boom!

The command will return a service url, click on that and whack a “/helloworld” to the end of url

Congratulations — you just built, containerized and deployed a production grade server written entirely in Dart.

If you want to do more with it, check out the Alfred docs. They are pretty easy to understand, especially if you have ever used ExpressJS before.

The full source code for this tutorial is available here:

https://github.com/rknell/dart-webserver-tutorial

--

--