Searchers landing on golang read multiple lines often want one of two things: a golang multiline string (or go multiline string) in source code, or golang read stdin / golang read line from stdin at runtime. This page covers both: raw and escaped multiline string golang forms, then read from stdin golang patterns with fmt.Scan, bufio.Reader.ReadString, and bufio.Scanner. Rows like python read multiple lines from stdin are a different language; golang multiline comment syntax (/* */) is about comments, not string values—see the FAQ. For splitting typed tokens from one line, see parse multiple inputs in Go.
Checked with Go 1.24 on 64-bit Linux (Fedora and Ubuntu family).
golang multiline string literals
Raw multiline string golang (backticks)
A raw string literal uses backticks and can span lines; characters are taken literally (no \n escapes—real newlines are allowed):
package main
import "fmt"
func main() {
query := `SELECT id, name
FROM users
WHERE active = true;`
fmt.Println(query)
}You should see the SQL-shaped text printed with embedded line breaks.
Double-quoted go multiline string
Inside double quotes you use \n for newlines; the string can still be written on one source line or broken with adjacent string literals:
package main
import "fmt"
func main() {
s := "line one\n" +
"line two\n"
fmt.Print(s)
}Backticks cannot contain a backtick; if you need one inside the text, use "..." with escapes or concatenation.
golang read stdin: multiple lines and whole stdin
fmt.Scan: tokens, not full lines
fmt.Scan splits on whitespace (newlines count as whitespace), so it is poor for golang line input that contains spaces. It fits multiple words from separate lines only when each line has a single token:
package main
import (
"fmt"
"log"
)
func main() {
var a, b, c string
if _, err := fmt.Scan(&a, &b, &c); err != nil {
log.Fatal(err)
}
fmt.Println(a, b, c)
}Paste three whitespace-separated tokens (each line can be one word); the program prints them on one line.
bufio.Reader: ReadString and io.EOF
ReadString('\n') keeps the delimiter. Treat io.EOF when the stream ends (pipe closed or Ctrl+D on a terminal) instead of treating every error as fatal:
package main
import (
"bufio"
"fmt"
"io"
"log"
"os"
"strings"
)
func main() {
fmt.Println("Enter lines; empty line ends:")
r := bufio.NewReader(os.Stdin)
var lines []string
for {
line, err := r.ReadString('\n')
if err != nil {
if err == io.EOF {
if strings.TrimSpace(line) != "" {
lines = append(lines, line)
}
break
}
log.Fatal(err)
}
if strings.TrimSpace(line) == "" {
break
}
lines = append(lines, line)
}
fmt.Println("count:", len(lines))
for _, ln := range lines {
fmt.Print(ln)
}
}Each stored line still ends with \n unless you strings.TrimSuffix it.
bufio.Scanner: idiomatic golang read line from stdin
Scanner is the usual golang read line from stdin choice: call Scan in a loop and read Text(); check Err after the loop. Tokens omit the trailing newline.
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
fmt.Println("Enter lines; empty line ends:")
sc := bufio.NewScanner(os.Stdin)
var lines []string
for sc.Scan() {
line := sc.Text()
if line == "" {
break
}
lines = append(lines, line)
}
if err := sc.Err(); err != nil {
log.Fatal(err)
}
for _, ln := range lines {
fmt.Println(ln)
}
}Default Scanner token size is limited (MaxScanTokenSize); very long single lines need Buffer or a Reader.
Sentinel line instead of an empty line
End input on a line containing only q after trimming:
package main
import (
"bufio"
"fmt"
"log"
"os"
"strings"
)
func main() {
sc := bufio.NewScanner(os.Stdin)
var lines []string
for sc.Scan() {
line := sc.Text()
if strings.EqualFold(strings.TrimSpace(line), "q") {
break
}
lines = append(lines, line)
}
if err := sc.Err(); err != nil {
log.Fatal(err)
}
for _, ln := range lines {
fmt.Println(ln)
}
}Summary
Golang multiline string work is done in the editor with backticks or \n in quotes—unrelated to golang read stdin. For read from stdin golang programs, fmt.Scan is for whitespace-separated tokens, bufio.Reader.ReadString keeps newlines and must handle io.EOF, and bufio.Scanner is the common golang read line from stdin loop with clean Text() values and an Err check at the end. Ignore off-topic rows like python read multiple lines from stdin here, and use /* */ only when you mean a golang multiline comment, not a runtime string.

