Reading data from console in Go is essential for building interactive CLI applications. When we say reading data, there are many different sources from where we can read the data. For instance, we can read input from the screen (which is the focus of this post) and this is called standard input. Additionally, Go gives us the access to it by means of os.Stdin. Furthermore, whatever user types are piped in we will be able to access it.
There are three easy ways to read input in Go
- Single Word / number (token)
- A full Line (including spaces)
- Many lines in a loop

Reading Single word/Number Input
We make use of fmt.Scan method for reading the inputs, for example inputs are Name age, we can read it like this
package main
import "fmt"
func main() {
var name string
var age int
fmt.Print("Enter name and age (example: Siva 35): ")
_, err := fmt.Scan(&name, &age)
if err != nil {
fmt.Println("Input error:", err)
return
}
fmt.Printf("Hello %s! You are %d years old.\n", name, age)
}
func Scan
func Scan(a ...any) (n int, err error)Scan scans text read from standard input, storing successive space-separated values into successive arguments. Newlines count as space. It returns the number of items successfully scanned. If that is less than the number of arguments, err will report why.[Official documentation]
In our program, we are omitting the second first parameter by using the literal _ and checking for any errors. Moreover, this pattern is common across the Go language and most of the error handling follows this approach.
The reference to the variable name and age is passed to Scanf where the method will read and assign the values. Pointer references are used here; you can read about this in operators. More information about this will be covered going forward.
- You cannot input string with spaces
A full Line (including spaces)
bufio.Reader is used for reading full line and then parse the input , bufio wraps an ioReader and adds buffering helpful text mehtod
ReadString('\n') reads until the first occurrence of the delimiter (and includes it). If it hits an error before finding the delimiter, it returns what it read + the error (often io.EOF).
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter full name: ")
fullName, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Read error:", err)
return
}
fullName = strings.TrimSpace(fullName)
fmt.Print("Enter age: ")
ageLine, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Read error:", err)
return
}
ageLine = strings.TrimSpace(ageLine)
age, err := strconv.Atoi(ageLine)
if err != nil {
fmt.Println("Age must be a number:", err)
return
}
fmt.Printf("Name=%q Age=%d\n", fullName, age)
}
Even thought this approach looks boring it is very predictable and easy to maintain.
Many lines in a loop
Scanner is great when you want to loop over input tokens (lines, words, bytes) using a split function.
Important limitation: scanning stops if a token is too large to fit in the scanner buffer. By default, the max token size is MaxScanTokenSize (64K).
You can increase the limit using scanner.Buffer(...), but you must do it before scanning starts (calling Buffer after scanning begins panics).
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
sc := bufio.NewScanner(os.Stdin)
// Optional: allow longer lines than the default max token size.
buf := make([]byte, 0, 64*1024)
sc.Buffer(buf, 1024*1024) // up to 1MB tokens
for sc.Scan() {
fmt.Println("LINE:", sc.Text())
}
if err := sc.Err(); err != nil {
fmt.Println("Scan error:", err)
}
}
Which approach is better for reading data from console in Go?
“Better” depends on what your input looks like.
Quick decision guide
- User types a few values (tokens) →
fmt.Scan/fmt.Scanln
(fast to write, minimal code) - User types sentences or values with spaces →
bufio.Reader+ parse
(ReadString('\n')/ReadBytes('\n')) - You’re processing a stream line-by-line (stdin may be piped) →
bufio.Scanner
(simple loop; watch token size)
A practical “default” recommendation
For most real CLI apps (prompts, validation, user-friendly errors), start with bufio.Reader.
Use fmt.Scan for quick demos.
Use bufio.Scanner for line-by-line stream processing.
However, we will not use these in practical application as there are other libraries that will help us to deal with reading input , command line arguments in a better way.



