diff --git a/09-merge-channels/README.md b/09-merge-channels/README.md
new file mode 100644
index 0000000..e958d52
--- /dev/null
+++ b/09-merge-channels/README.md
@@ -0,0 +1,13 @@
+# Merge Channels
+Implement the `Merge` function that takes a variable number of input channels and returns a single output channel. The output channel should receive all values from all input channels. Once all input channels are closed and all values have been sent to the output channel, the output channel should be closed.
+
+Requirements:
+
+1. The function should handle any number of input channels, including zero.
+2. All values from all input channels must be sent to the output channel.
+3. The output channel should be closed only after all input channels are closed and all values have been forwarded.
+4. Your implementation must not leak goroutines.
+5. Values should be forwarded as soon as they are available from any input channel.
+
+## Tags
+`Concurrency`
diff --git a/09-merge-channels/solution/solution.go b/09-merge-channels/solution/solution.go
new file mode 100644
index 0000000..25e1c43
--- /dev/null
+++ b/09-merge-channels/solution/solution.go
@@ -0,0 +1,24 @@
+package main
+
+import "sync"
+
+func Merge(channels ...<-chan int) <-chan int {
+	out := make(chan int)
+	var wg sync.WaitGroup
+	for _, in := range channels {
+		wg.Add(1)
+		go func() {
+			for val := range in {
+				out <- val
+			}
+			wg.Done()
+		}()
+	}
+
+	go func() {
+		wg.Wait()
+		close(out)
+	}()
+
+	return out
+}
diff --git a/09-merge-channels/task.go b/09-merge-channels/task.go
new file mode 100644
index 0000000..9756452
--- /dev/null
+++ b/09-merge-channels/task.go
@@ -0,0 +1,5 @@
+package main
+
+func Merge(channels ...<-chan int) <-chan int {
+	return nil
+}
diff --git a/09-merge-channels/task_test.go b/09-merge-channels/task_test.go
new file mode 100644
index 0000000..3eb3f3c
--- /dev/null
+++ b/09-merge-channels/task_test.go
@@ -0,0 +1,75 @@
+package main
+
+import (
+	"reflect"
+	"sort"
+	"testing"
+)
+
+func TestMerge(t *testing.T) {
+	tests := []struct {
+		name   string
+		values [][]int
+		result []int
+	}{
+		{
+			name:   "empty input",
+			values: [][]int{},
+			result: []int{},
+		},
+		{
+			name:   "single empty channel",
+			values: [][]int{{}},
+			result: []int{},
+		},
+		{
+			name:   "single channel with values",
+			values: [][]int{{3, 1, 4}},
+			result: []int{1, 3, 4},
+		},
+		{
+			name:   "multiple channels with balanced load",
+			values: [][]int{{9, 3}, {8, 2}, {7, 1}},
+			result: []int{1, 2, 3, 7, 8, 9},
+		},
+		{
+			name:   "channels with uneven distributions",
+			values: [][]int{{5}, {}, {1, 2, 3, 4}},
+			result: []int{1, 2, 3, 4, 5},
+		},
+		{
+			name:   "channels with duplicate values",
+			values: [][]int{{1, 3}, {1, 3}, {3}},
+			result: []int{1, 1, 3, 3, 3},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			channels := []<-chan int{}
+			for _, chValues := range tt.values {
+				ch := make(chan int)
+				channels = append(channels, ch)
+				go func() {
+					for _, val := range chValues {
+						ch <- val
+					}
+					close(ch)
+				}()
+			}
+			out := Merge(channels...)
+
+			result := []int{}
+			for val := range out {
+				result = append(result, val)
+			}
+
+			sort.Ints(tt.result)
+			sort.Ints(result)
+
+			if !reflect.DeepEqual(tt.result, result) {
+				t.Errorf("Expected: %+q, got: %+q", tt.result, result)
+			}
+		})
+	}
+}
diff --git a/README.md b/README.md
index 632d1d9..644253a 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,7 @@ Here is a list of the problems available in the repository. Problems are organiz
 * [Rate Limiter](06-rate-limiter/)
 * [TTL Cache](07-ttl-cache/)
 * [Request With Failover](08-request-with-failover/)
+* [Merge Channels](09-merge-channels/)
 
 ## Contributing