}

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

Conversion Function Returns Notes
stringint strconv.Atoi(s) (int, error) Decimal only, most common
stringint64 strconv.ParseInt(s, base, bits) (int64, error) Any base 2–36
stringuint64 strconv.ParseUint(s, base, bits) (uint64, error) Unsigned variant
stringfloat64 strconv.ParseFloat(s, bits) (float64, error) 32 or 64 bit
intstring strconv.Itoa(n) string Fastest, decimal only
int64string strconv.FormatInt(n, base) string Any base 2–36
uint64string strconv.FormatUint(n, base) string Unsigned variant
anystring fmt.Sprintf("%d", n) string Flexible, slightly slower
intrune char string(rune(n)) string Unicode 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