Getting Started with Akka-Streams

Reading Time: 4 minutes

As the world is growing, so is the data. And analysis of this data has become important. But how will you do it? How will you work with the data whose size is unknown to you? A solution to this scenario is Akka-Streams and here I’m going to discuss it.

In this blog you will get to know the basics of Akka-Streams just to get you started. So, let’s begin !!

What is Akka Stream?

First we should know, what is a stream? So , the word stream means “steady flow of something” and here we have a flow of data. Stream is basically a sequence of data that can be infinite. Here, infinite means very huge size to fit in your system’s memory or just unknown to you.

Now, you understand streams, go through following to understand akka-streams:

  • Akka-Stream is a module built on top of Akka Actors. It means there are underlying actors that are actually working in transferring data.
  • It is a library to process and transfer a sequence of elements.
  • Akka Streams is nonblocking that means a certain operation does not hinder the progress of the calling thread.
  • It provides easy-to-use APIs to create streams that leverage the power of the Akka toolkit without explicitly defining actor behaviors and messages. That means, a relief from handling actors yourself.
  • We can focus on logic rather than focusing on how to manage actors and that can be much productive.

Basic Terminology in Akka-Streams


A source
A Source
  • This is the entry point to your stream/ input to a stream.
  • It has only one output point.
  • It can receive data from file,database,message queue, collection etc.
  • Defines as Source[+Out,+Mat]
    • Out is the type of element source produces
    • Mat is the type of materialized value.
  • We can consider the source as producer that ingest the data into the stream.
  • Sources receive demand from downstream.
  • A source can send data as long as there is demand.
  • If there is no demand no data is sent.
  • The Source has to handle the incoming stream when there is no demand

Example of Sources

  • Source.empty[+Out]
 val emptySource: Source[Int, NotUsed] = Source.empty[Int]
  • Source.single
val single: Source[String, NotUsed] = Source.single("no repetition")
  • Source.tick
val delayBased: Source[String, Cancellable] = Source.tick(initialDelay = 1.second,
    interval = 5.seconds,
    tick = "I'll be sent after the delay")
  • Source generated from range
 val numbers: Source[Int, NotUsed] = Source(1 to 10)


A sink
A Sink
  • This is the exit point of your stream/output to a stream.
  • It has only one input point.
  • It can write data to a file, database, message queue, collection etc.
  • Defined as Sink[+In,+Mat]
    • In is the type of the element that Sink consumes.
    • Mat is the type of materialized value.
  • We can consider the sink as subscriber that takes the data from the stream.
  • Sink send demand to the source.
  • A sink should only send the demand when it is ready to receive the data.
  • If it doesn’t consume incoming data, flow will cease and demand will stop.

Examples of Sink

  • Sink.ignore
val ignoreSink: Sink[Any, Future[Done]] = Sink.ignore
  • Sink.foreach
val sideEffectSink: Sink[Any, Future[Done]] = Sink.foreach(element => println(element))
  • Sink.fold
val sum: Sink[Int, Future[Int]] = Sink.fold(0) { case (sum, ele) => sum + ele }


A flow
A Flow
  • The flow is a processing step within the stream.
  • It has one input and one output point.
  • It combines one incoming channel and one outgoing channel as well as some transformation of the messages passing through it.
  • Flow connected with a Source creates a new Source.
  • Flow connected with a Sink creates a new Sink.
  • Define as Flow[+In,+Out,+Mat]
    • In defines the type of the element that the flow consumes.
    • Out defines the type of the element that the flow produces.
    • Mat defines the type of materialized value.

Examples of Flow

 val flowToDouble: Flow[Int, Int, NotUsed] = Flow[Int].map(_ * 2)
val groupTwo: Flow[Int, Seq[Int], NotUsed] = Flow[Int].grouped(2)

Runnable Graph

A runnable graph
A simple linear Graph
  • Source , Sink and Flows doesn’t do anything themselves. They are just like templates. We can reuse them.
  • They should be connected to start the flow and that makes a Runnable Graph.
  • A simple runnable graph can be created by using via and to methods on a source( the simplest way).
    • Via connects to a flow. There could be multiple flows.
    • To connects to a sink.
  • Via and to methods can also be used on a flow rather than source.

We can also use runwith instead of to, as follows :



It is the process of taking the stream and allocating required resources to it. It also includes starting the actor, opening files, etc whatever the stream requires. When the materialization occurs it produces a materialized value for the stream. 

Materialization of a stream is done when there is some terminal command like run or command like runwith etc. Without materialization there won’t be any functioning as required resources won’t be provided.

Back pressure

It is a way for consumers of data to notify the producers about their current availability. It can also slow down the producer to meet it’s consumption need. In the scenario when there is a producer that is producing data at a very high rate and consumer is slow, then there could be problem. For this, there is a concept of back pressure.

Back pressure is non blocking in nature, as the requests sent to producer to slow down are as messages which are asynchronous in nature.

Although, as akka-stream user we don’t have to worry about writing back-pressure algorithm. It is in-built in akka-streams and automatically applied. 

So that’s it for this blog. This was just a introduction to akka-streams and I hope it was helpful to you. For the full code you can go here. I’ll be writing more blogs on akka-streams. So, stay tuned !!


Akka-Stream Documentation