Question
I want to read standard input from the command line in Go, similar to Console.ReadLine() in C#. However, my program often exits before I can enter anything. What is the correct way to read console input in Go?
Here is my current code:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
fmt.Println(text)
fmt.Println("Enter text: ")
text2 := ""
fmt.Scanln(text2)
fmt.Println(text2)
ln := ""
fmt.Sscanln("%v", ln)
fmt.Println(ln)
}
I am looking for the Go equivalent of reading a full line from standard input, and I also want to understand why the other attempts do not work as expected.
Short Answer
By the end of this page, you will understand how to read input from standard input in Go, when to use bufio.Reader versus fmt.Scanln, and why some input attempts fail. You will also learn beginner-friendly patterns for reading full lines, single values, and handling common input mistakes.
Concept
In Go, reading from standard input means reading data from os.Stdin, which represents what the user types in the terminal.
There are two common approaches:
bufio.Readerfor reading full lines or larger chunks of textfmt.Scan,fmt.Scanln, orfmt.Scanffor scanning space-separated values into variables
If you want behavior similar to C#'s Console.ReadLine(), the closest match is usually reading from os.Stdin with bufio.Reader.
Why this matters
Console input is useful in many kinds of programs:
- small command-line tools
- coding challenge programs
- interactive scripts
- configuration prompts
- debugging utilities
A key detail in Go is that some input functions expect pointers to variables. If you pass a normal value instead of a pointer, the function cannot store the result in your variable.
For example, this is wrong:
text2 := ""
fmt.Scanln(text2)
This passes the value of text2, not its address. Go needs the address so it can write the input into that variable.
Correct version:
Mental Model
Think of standard input as a stream of characters flowing from the keyboard into your program.
os.Stdinis the pipe connected to the keyboard inputbufio.Readeris a helper that lets you collect characters until a stopping point, such as a newlinefmt.Scanlnis more like a form parser: it reads typed values and places them into variables you provide
A simple analogy:
bufio.Reader= reading an entire sentence from a notebook linefmt.Scanln= filling labeled boxes with typed values
If you want the whole line exactly as the user typed it, use a reader. If you want individual values like a name, age, or number, scanning functions can be simpler.
Syntax and Examples
Read a full line with bufio.Reader
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
text, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Error:", err)
return
}
text = strings.TrimSpace(text)
fmt.Println("You entered:", text)
}
Explanation
bufio.NewReader(os.Stdin)creates a reader connected to keyboard input.ReadString('\n')keeps reading until the user presses Enter.- The returned text usually includes the newline, so
strings.TrimSpace()is often used to remove it.
Read a single word with fmt.Scanln
package main
import "fmt"
func {
name
fmt.Print()
_, err := fmt.Scanln(&name)
err != {
fmt.Println(, err)
}
fmt.Println(, name)
}
Step by Step Execution
Consider this example:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Error:", err)
return
}
input = strings.TrimSpace(input)
fmt.Println("Final value:", input)
}
What happens step by step
-
reader := bufio.NewReader(os.Stdin)- A reader is created that listens to terminal input.
-
fmt.Print("Enter text: ")- The prompt is shown without adding a newline.
-
input, err := reader.ReadString('\n')- The program pauses and waits.
- The user types something like
hello worldand presses Enter. - The value returned is usually
"hello world\n".
Real World Use Cases
Reading from standard input is common in practical Go programs.
Command-line utilities
A script may ask for a filename, search term, or confirmation:
fmt.Print("Enter filename: ")
Coding challenge platforms
Many competitive programming tasks read data from standard input instead of from files or prompts.
Setup scripts
A tool might ask for environment values:
- database host
- port number
- API key label
Interactive admin tools
Terminal apps often request commands like:
createdeletelist
Data entry programs
You may ask the user to enter names, quantities, or notes, then process those values inside the program.
Real Codebase Usage
In real Go codebases, developers usually choose the input tool based on the shape of the data.
Common patterns
Full-line input for free-form text
Used for:
- search queries
- comments
- prompts with spaces
- file paths
Typical choice:
reader := bufio.NewReader(os.Stdin)
line, err := reader.ReadString('\n')
Token-based input for structured values
Used for:
- menu choices
- numbers
- short identifiers
Typical choice:
var choice int
fmt.Scanln(&choice)
Validation after input
Developers rarely trust raw input directly.
if strings.TrimSpace(name) == "" {
fmt.Println("Name cannot be empty")
return
}
Early returns on input errors
A very common Go style is:
input, err := reader.ReadString('\n')
if err != nil {
}
Common Mistakes
1. Passing a value instead of a pointer
Broken code:
var name string
fmt.Scanln(name)
Problem:
Scanlncannot write intonamebecause it needs a pointer.
Correct code:
var name string
fmt.Scanln(&name)
2. Using fmt.Sscanln for terminal input
Broken code:
var name string
fmt.Sscanln("%v", name)
Problem:
Sscanlnscans from a string, not from standard input.- It is the wrong function for keyboard input.
Correct approach:
fmt.Scanln(&name)
or
reader := bufio.NewReader(os.Stdin)
text, _ := reader.ReadString('\n')
3. Ignoring errors
Comparisons
| Approach | Best for | Reads spaces? | Needs pointer? | Notes |
|---|---|---|---|---|
bufio.Reader.ReadString('\n') | Full lines | Yes | No | Closest to Console.ReadLine() |
bufio.Scanner | Line-by-line input | Yes | No | Simple and clean for basic line reading |
fmt.Scan | Space-separated values | No | Yes | Reads tokens until whitespace |
fmt.Scanln | Values on one line | Limited |
Cheat Sheet
Full line input
reader := bufio.NewReader(os.Stdin)
text, err := reader.ReadString('\n')
Remove newline:
text = strings.TrimSpace(text)
Single value input
var name string
_, err := fmt.Scanln(&name)
Important rule
Scanning functions need pointers:
fmt.Scanln(&value) // correct
fmt.Scanln(value) // wrong
Useful imports
import (
"bufio"
"fmt"
"os"
"strings"
)
Best tool by situation
- Full sentence or line:
bufio.Readerorbufio.Scanner - Single word or number:
fmt.Scanln - Parse from an existing string:
fmt.Sscanln
Common edge cases
FAQ
What is the Go equivalent of Console.ReadLine()?
The closest equivalent is usually reading from os.Stdin using bufio.Reader or bufio.Scanner.
Why does fmt.Scanln(text2) not work?
Because Scanln needs a pointer. Use fmt.Scanln(&text2) instead.
Should I use bufio.Reader or bufio.Scanner?
Use bufio.Scanner for simple line-by-line input. Use bufio.Reader when you want more control.
Does fmt.Sscanln read from the keyboard?
No. It reads from a string already in memory, not from standard input.
Why does my input contain a newline character?
Functions like ReadString('\n') include the newline in the returned string. Use strings.TrimSpace() to remove it.
Can fmt.Scanln read text with spaces?
Mini Project
Description
Build a small Go program that asks the user for their name and favorite programming language, then prints a friendly summary. This demonstrates how to read full-line console input safely and cleanly.
Goal
Create a console app that reads two lines of user input and displays them back without trailing newline characters.
Requirements
Requirement 1 Requirement 2 Requirement 3
Keep learning
Related questions
Blank Identifier Imports in Go: What `_` Means in an Import Statement
Learn what `_` means in a Go import, why blank identifier imports run package init code, and when to use them safely.
Check if a Value Exists in a Slice in Go
Learn how to check whether a value exists in a slice in Go, and why Go has no Python-style `in` operator for arrays or slices.
Concatenating Slices in Go with append
Learn how to concatenate two slices in Go using append and the ... operator, with examples, pitfalls, and practical usage.