A Go string holds read-only bytes (usually UTF-8 text). A []byte is mutable. Converting go bytes to string is common for I/O, HTTP bodies, and protocols. For turning strings or readers into byte views, see byte slice to io.Reader. For concurrency basics when sharing data, see goroutines.
Tested with Go 1.24 on Linux.
Direct conversion: string(b)
The zero-cost pattern for valid UTF-8 (or treating bytes as opaque) is s := string(b).
package main
import "fmt"
func main() {
hello := []byte("Hello")
fmt.Println(string(hello))
empty := []byte{}
fmt.Printf("empty len=%d\n", len(string(empty)))
}You should see Hello and empty len=0.
Formatting with fmt.Sprintf
Use fmt.Sprintf when the byte slice is part of a larger formatted message.
package main
import "fmt"
func main() {
b := []byte("Go")
fmt.Printf("%s\n", b)
fmt.Println(fmt.Sprintf("Hello, %s!", b))
}strings.Builder and bytes.Buffer
Use strings.Builder when you append many fragments and then call String(). Use bytes.Buffer when you already mix binary reads and writes.
package main
import (
"bytes"
"fmt"
"strings"
)
func main() {
var sb strings.Builder
sb.Write([]byte("Hello"))
sb.WriteByte(',')
sb.Write([]byte(" world"))
fmt.Println(sb.String())
var buf bytes.Buffer
buf.WriteString("bytes.Buffer")
fmt.Println(buf.String())
}Numbers: strconv instead of casting
If bytes hold decimal digits, use strconv.ParseInt or Atoi—do not use string(b) for numeric parsing.
package main
import (
"fmt"
"strconv"
)
func main() {
n, err := strconv.Atoi(string([]byte("42")))
if err != nil {
panic(err)
}
fmt.Println(n + 1)
}You should see 43.
unsafe (not recommended)
The unsafe package can force a reinterpretation of memory. It is rarely justified for []byte→string in application code: it breaks invariants if the slice mutates, and future compiler changes can make subtle bugs. Prefer string(b) unless a profiler shows a proven hotspot and you follow the unsafe documentation carefully.
Summary
For go bytes to string, start with string(b) for simple UTF-8 or opaque bytes. Use fmt.Sprintf for formatted output, strings.Builder or bytes.Buffer for incremental assembly, and strconv when the bytes represent encoded numbers. Avoid unsafe unless you have a measured need and strong review. Use io.ReadAll (not deprecated ioutil) when reading from an io.Reader.

