Golang byte to int: Convert `byte` and `[]byte` Correctly

Deepak Prasad
Tested on RHEL 10.2 with Go 1.27.0
Package go 1.27.0
Applies to Any host with Go 1.20+ installed
Privilege Normal user
Scope Single byte widening, decimal text with strconv, fixed-width and varint binary with encoding/binary, large magnitudes with math/big, and reverse int-to-bytes patterns. Does not cover Protocol Buffers or full protocol design.
Related guides Go bytes to string
strconv in Go
Convert int to string in Go
Type casting in Go
Golang tutorial

A single byte is just uint8 and converts with int(b). A []byte has no single integer meaning: it might hold decimal text, fixed-width binary, a varint, or a large unsigned magnitude. There is no universal []byteint conversion—first identify the encoding, then pick the API.

Input Use
Single byte / uint8 int(b)
[]byte("123") strconv.Atoi(string(b))
Fixed 2/4/8-byte integer encoding/binary
Varint-encoded integer binary.Varint / binary.Uvarint
Arbitrarily large unsigned big-endian magnitude big.Int.SetBytes

Convert a single byte or uint8 to int

byte is a type alias for uint8. Widening to int preserves the numeric value from 0 through 255:

go
var b byte = 200
n := int(b) // 200

No packages are required. This is not how you convert a []byte slice—one byte is a scalar; a slice needs an encoding interpretation.


Convert decimal text []byte to int

When the bytes represent decimal digits (and optional leading sign), convert to string and parse:

go
package main

import (
	"fmt"
	"strconv"
)

func main() {
	b := []byte("123")
	n, err := strconv.Atoi(string(b))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(n)
}
text
123

After string(b), the text must match the integer syntax accepted by strconv.Atoi or strconv.ParseInt—decimal digits with an optional sign. []byte{54, 60, 70} fails because "6<F" is not valid decimal syntax, not because of a special UTF-8 rule for byte slices.

Always check err. Atoi returns (0, err) on failure; ignoring the error makes zero indistinguishable from a real zero.

Atoi vs ParseInt

Use strconv.Atoi for ordinary machine-sized decimal integers. Reach for strconv.ParseInt(s, base, bitSize) when you need an explicit base, a fixed maximum bit width, or an int64 result:

go
v, err := strconv.ParseInt(string(b), 10, 32) // int32 range

For unsigned decimal text, use strconv.ParseUint with the appropriate bit size.


Convert fixed-width binary bytes to an integer

If the bytes come from a protocol or file format, you must know the field width, byte order, and signedness before decoding.

When you already hold exactly four bytes in wire order, Uint32 is clearer than wrapping the slice in bytes.NewReader and binary.Read:

go
buf := []byte{0x00, 0x00, 0x00, 0x7b}
if len(buf) < 4 {
	// handle short buffer
}
u := binary.BigEndian.Uint32(buf)
text
123

Use binary.LittleEndian.Uint32 when the format stores least-significant byte first. The same numeric value can appear as 00 00 00 7b in big-endian form or 7b 00 00 00 in little-endian form—the slice alone does not tell Go which convention applies.

BigEndian vs LittleEndian

Pick the endianness from your specification, not from the bytes on disk. Mixing encode and decode endianness silently produces the wrong integer.

Signed int32 and int64

For signed two's-complement wire data, read the unsigned width first, then reinterpret the bits:

go
signed := int32(binary.BigEndian.Uint32(buf))

For eight-byte fields, use Uint64 / PutUint64 with the same pattern. On the wire, prefer fixed int16, uint16, int32, uint32, int64, and uint64 types rather than architecture-dependent int; convert to int in application code only when appropriate.

binary.Read remains useful when bytes arrive from an io.Reader or you want the decoder to advance a cursor—Uint32 on a slice you already have is the simpler path.


Decode varint-encoded bytes

Varints store smaller values in fewer bytes using a different encoding than ASCII decimal or fixed-width integers. Decode them with:

go
n, bytesRead := binary.Uvarint(buf) // unsigned
// or
n, bytesRead := binary.Varint(buf)  // signed

Sample output for []byte{0xac, 0x02}:

text
300 2

Interpret bytesRead carefully: greater than zero means success; zero means the buffer is too small; less than zero signals overflow (the magnitude of the negative value is the minimum buffer size needed). This is not interchangeable with Atoi or Uint32.


Convert large byte sequences with math/big

When the slice is an unsigned big-endian magnitude of arbitrary length, use math/big:

go
i := new(big.Int).SetBytes([]byte{0x01, 0x00, 0x01})
fmt.Println(i.String()) // 65537

SetBytes interprets the bytes as an unsigned big-endian magnitude. It does not decode little-endian layouts or signed two's-complement formats automatically. The result is *big.Int, not a native Go int—convert or compare through big.Int methods when values may exceed machine word size.


Convert integers back to []byte

Match the reverse path to how you decoded.

Decimal text

go
[]byte(strconv.Itoa(n))

Use strconv.FormatInt or FormatUint when you need int64 or a specific base.

Fixed-width binary

go
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, uint64(n))

Use the same endianness and width on encode and decode.

Modern append APIs

Go 1.19 added AppendUint16, AppendUint32, and AppendUint64 through AppendByteOrder, plus AppendVarint and AppendUvarint. Generic binary.Append arrived in Go 1.23—do not confuse it with the 1.19 append helpers.


Common conversion mistakes

Mistake Fix
Treating byte and []byte as equivalent A byte is one uint8; a slice needs an encoding interpretation
Calling Atoi on arbitrary binary data Use it only for textual integers
Ignoring the Atoi error Invalid input otherwise looks like a real zero
Guessing endian order Follow the protocol or file format
Calling Uint32 with fewer than 4 bytes Validate len(buf) before fixed-width reads
Encoding native int directly on a wire protocol Use fixed-width integer types on the wire
Assuming big.Int.SetBytes decodes signed data It reads an unsigned big-endian magnitude
Saying generic binary.Append exists since Go 1.19 It was added in Go 1.23

Summary

There is no universal []byte to int conversion because a byte slice does not describe how the number was encoded. Widen a single byte with int(b). For slices, choose strconv when the bytes are decimal text, encoding/binary for fixed-width or varint wire layouts, and math/big for large unsigned magnitudes.

Check parse errors, validate buffer lengths, and match endianness to your format. Convert wire integers with fixed widths (uint32, int64, and so on) rather than native int when the bytes leave your process.


References


Frequently Asked Questions

1. How do I convert a single byte to int in Go?

byte is an alias for uint8. Widen with int(b); the numeric value stays in the 0–255 range. This applies to one byte only, not to a []byte slice.

2. How do I convert []byte("123") to an integer?

When the slice holds decimal text, use strconv.Atoi(string(b)) or strconv.ParseInt with an explicit base and bit size. Always check the returned error.

3. Can I cast a []byte directly to int?

No. A byte slice does not describe how the number was encoded. Pick strconv for text, encoding/binary for fixed-width or varint wire data, or math/big for large unsigned magnitudes.

4. How do I convert four bytes to an int32 or uint32?

Use binary.BigEndian.Uint32(buf) or binary.LittleEndian.Uint32(buf) when you know the width and byte order. Cast to int32 for signed two-complement bits. Validate len(buf) before slicing.

5. How do I know whether to use BigEndian or LittleEndian?

Follow the protocol, file format, or platform convention that produced the bytes. The slice itself does not tell Go which endianness to use.

6. How do I convert a negative integer to and from bytes?

For fixed-width wire formats, write and read with PutUint64/Uint64 or PutUint32/Uint32 using the same endianness, casting between int and uint to preserve two-complement bits. big.Int SetBytes reads unsigned magnitudes only.

7. What is the difference between fixed-width integers and varints?

Fixed-width fields use a set number of bytes in a chosen byte order. Varints use a variable number of bytes and a different encoding; decode them with binary.Varint or binary.Uvarint, not Uint32 or Atoi.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops robust solutions and implements efficient data processing and management strategies across various projects and platforms.

  • Go (programming language)
  • Python (programming language)
  • Java (programming language)
  • MongoDB
  • Kubernetes