Go: Convert String to Int (and Int to String) — Complete Guide (2026)

Go: Convert String to Int (and Int to String) — Complete Guide (2026)

To convert a string to an int in Go, use strconv.Atoi(s). It returns (int, error) — always check the error. To convert an int back to a string, use strconv.Itoa(n).

n, err := strconv.Atoi("42")
if err != nil {
    log.Fatal(err)
}
fmt.Println(n + 1)   // 43

s := strconv.Itoa(42)
fmt.Println(s + "!")   // "42!"

Why You Cannot Add Strings and Ints Directly

Go does not perform implicit type conversions. If you try to concatenate a string with a number, you get a compile error:

age := 30
msg := "I am " + age + " years old"
// invalid operation: "I am " + age (mismatched types string and int)

You must convert explicitly. This guide covers every conversion method with when to use each.


String to Int: strconv.Atoi

Atoi stands for "ASCII to integer". It converts a decimal string to int (the platform-native integer size — 64-bit on 64-bit systems).

package main

import (
    "fmt"
    "strconv"
)

func main() {
    s := "123"
    n, err := strconv.Atoi(s)
    if err != nil {
        fmt.Printf("conversion failed: %v\n", err)
        return
    }
    fmt.Println(n + 1)   // 124
}

What errors look like:

n, err := strconv.Atoi("abc")
// err: strconv.Atoi: parsing "abc": invalid syntax

n, err = strconv.Atoi("99999999999999999999")
// err: strconv.Atoi: parsing "99999999999999999999": value out of range

When to use Atoi: When you need a plain int from a decimal string. This covers 90% of use cases — parsing command-line arguments, reading config values, processing CSV fields.


String to Int64: strconv.ParseInt

ParseInt offers full control: you specify the base (2–36) and the bit size (0, 8, 16, 32, 64).

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // Decimal (base 10), fit into int64
    n, err := strconv.ParseInt("9876543210", 10, 64)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(n)   // 9876543210

    // Hexadecimal (base 16)
    h, _ := strconv.ParseInt("1a2b", 16, 64)
    fmt.Println(h)   // 6699

    // Binary (base 2)
    b, _ := strconv.ParseInt("1010", 2, 64)
    fmt.Println(b)   // 10

    // Octal (base 8)
    o, _ := strconv.ParseInt("0755", 8, 64)
    fmt.Println(o)   // 493
}

Bit size parameter: - 0 — infer from the string prefix (0x → 16, 0 → 8, else 10), fit into int - 32 — value must fit in int32; returned as int64 (cast to int32 is safe) - 64 — value must fit in int64

For unsigned integers use strconv.ParseUint:

u, err := strconv.ParseUint("255", 10, 8)   // fits in uint8
fmt.Println(uint8(u))   // 255

String to Float: strconv.ParseFloat

f, err := strconv.ParseFloat("3.14159", 64)
if err != nil {
    log.Fatal(err)
}
fmt.Println(f * 2)   // 6.28318

Int to String: strconv.Itoa

Itoa is the reverse of Atoi — integer to ASCII string, base 10.

n := 42
s := strconv.Itoa(n)
fmt.Println(s)          // "42"
fmt.Println(s + "px")   // "42px"

This is the fastest and most idiomatic way to convert int to string in Go.


Int to String: strconv.FormatInt

FormatInt handles any base and any int64:

// Decimal
fmt.Println(strconv.FormatInt(255, 10))   // "255"

// Hexadecimal
fmt.Println(strconv.FormatInt(255, 16))   // "ff"

// Binary
fmt.Println(strconv.FormatInt(255, 2))    // "11111111"

// Octal
fmt.Println(strconv.FormatInt(255, 8))    // "377"

Int to String: fmt.Sprintf

fmt.Sprintf is the most flexible — it formats any combination of values into a string using format verbs:

n := 42
s := fmt.Sprintf("%d", n)               // "42"
s2 := fmt.Sprintf("count: %d items", n) // "count: 42 items"
s3 := fmt.Sprintf("%05d", n)            // "00042" (zero-padded, width 5)
s4 := fmt.Sprintf("%x", n)              // "2a" (hex lowercase)
s5 := fmt.Sprintf("%X", n)              // "2A" (hex uppercase)
s6 := fmt.Sprintf("%b", n)              // "101010" (binary)
s7 := fmt.Sprintf("%08b", n)            // "00101010" (binary, 8 wide)

When to use fmt.Sprintf vs strconv.Itoa: - Use strconv.Itoa when you only need the number as a string — it is faster and allocates less. - Use fmt.Sprintf when you need the number embedded in a larger string or formatted with padding/precision.


Common Mistake: string(int) is NOT a String Conversion

A frequent mistake by Go beginners:

n := 65
s := string(n)   // s is "A", not "65"!
fmt.Println(s)   // "A"

string(n) interprets the integer as a Unicode code point and returns the character at that code point. 65 is the Unicode code point for 'A'. This is rarely what you want.

The correct way:

n := 65
s := strconv.Itoa(n)   // "65"
fmt.Println(s)          // "65"

Error Handling Patterns

Pattern 1: Fatal on bad input (CLI tools)

func mustAtoi(s string) int {
    n, err := strconv.Atoi(s)
    if err != nil {
        log.Fatalf("invalid number %q: %v", s, err)
    }
    return n
}

port := mustAtoi(os.Args[1])

Pattern 2: Default value on bad input

func atoiOrDefault(s string, def int) int {
    n, err := strconv.Atoi(s)
    if err != nil {
        return def
    }
    return n
}

timeout := atoiOrDefault(os.Getenv("TIMEOUT_SECS"), 30)

Pattern 3: Collect all errors

type parseError struct {
    field string
    err   error
}

func parseConfig(m map[string]string) (int, int, []parseError) {
    var errs []parseError
    port, err := strconv.Atoi(m["port"])
    if err != nil {
        errs = append(errs, parseError{"port", err})
    }
    workers, err := strconv.Atoi(m["workers"])
    if err != nil {
        errs = append(errs, parseError{"workers", err})
    }
    return port, workers, errs
}

Base Conversions Between Strings

// Hex string "ff" → decimal int 255
n, _ := strconv.ParseInt("ff", 16, 64)
fmt.Println(n)   // 255

// Decimal int 255 → hex string "ff"
s := strconv.FormatInt(255, 16)
fmt.Println(s)   // "ff"

// Decimal string "255" → binary string "11111111"
n2, _ := strconv.ParseInt("255", 10, 64)
fmt.Println(strconv.FormatInt(n2, 2))   // "11111111"

Method Comparison Table

ConversionFunctionReturnsNotes
string → intstrconv.Atoi(s)(int, error)Decimal only, most common
string → int64strconv.ParseInt(s, base, bits)(int64, error)Any base 2–36
string → uint64strconv.ParseUint(s, base, bits)(uint64, error)Unsigned variant
string → float64strconv.ParseFloat(s, bits)(float64, error)32 or 64 bit
int → stringstrconv.Itoa(n)stringFastest, decimal only
int64 → stringstrconv.FormatInt(n, base)stringAny base 2–36
uint64 → stringstrconv.FormatUint(n, base)stringUnsigned variant
any → stringfmt.Sprintf("%d", n)stringFlexible, slightly slower
int → rune charstring(rune(n))stringUnicode code point, not the digit

FAQ

Q: What is the difference between strconv.Atoi and strconv.ParseInt?

A: Atoi(s) is equivalent to ParseInt(s, 10, 0) — base 10, fit into the native int size. ParseInt is more flexible: it handles hex, binary, octal, and lets you specify the bit size of the result. Use Atoi for ordinary decimal strings; use ParseInt when you need other bases or explicit sizing.

Q: Why does string(42) give me "*" instead of "42"?

A: In Go, string(intValue) converts the integer to the Unicode character at that code point. Code point 42 is *. To convert the number to its decimal string representation, use strconv.Itoa(42) which gives "42".

Q: What happens if the string has leading/trailing spaces?

A: strconv.Atoi(" 42 ") returns an error — strconv functions do not trim whitespace. Use strings.TrimSpace(s) first: strconv.Atoi(strings.TrimSpace(s)).


Related Articles

Leonardo Lazzaro

Software engineer and technical writer. 10+ years experience in DevOps, Python, and Linux systems.

More articles by Leonardo Lazzaro