Skip to main content


Let's say you have multiple sources of data, and you want to write that data into one input.

You can achieve that by using the io.MultiReader. io.MultiReader lets you connect multiple readers(sources of data) and read that data into an input sequentially.

func MultiReader(readers ...Reader) Reader

MultiReader returns a Reader that's the logical concatenation of the provided input readers. They're read sequentially. Once all inputs have returned EOF, Read will return EOF. If any of the readers return a non-nil, non-EOF error, Read will return that error.

The example from the standard library is easy to understand. It connects three readers into one, and then copy their data sequentially into os.Stdout which is a Writer:

package main

import (

func main() {
r1 := strings.NewReader("first reader ")
r2 := strings.NewReader("second reader ")
r3 := strings.NewReader("third reader\n")
r := io.MultiReader(r1, r2, r3)

if _, err := io.Copy(os.Stdout, r); err != nil {


run in Playground

To see that they are indeed read sequentially feel free to change the order of the readers' definition.

That was it: you now know how to connect multiple sources of data into one!

I hope by now you got used to viewing Readers as sources of data and Writers as placeholders of data. Once you get this mental model into your head you'll start seeing the opportunity of having your code full of Readers and Writers.

Soon, you'll see yourself as plumber which has to figure out how to connect the water pipes. The standard library gives you the tools to elegantly build your pipelines, you just need to learn about them!

Speaking of plumbing, did you know the Unix tee command got its name from the T-splitter used in plumbing? Feel free to play around with that command in your shell; in our next lesson we will learn about the io.TeeReader!