How to reverse a string in Go
Go has no strings.Reverse. Convert to runes, swap from both ends, convert back: runes := []rune(s) then walk i up and j down. Reversing []byte instead is the classic bug — it breaks every non-ASCII character.
A Go string is an immutable slice of bytes, not of characters, and it is conventionally UTF-8. That one fact decides the whole problem: é is two bytes, 言 is three, so reversing bytes shreds them, while reversing runes (Go's name for a Unicode code point) does the thing you meant. Each example runs on this page — hit Run, then edit the code and run it again.
1[]rune and a two-pointer swapRecommended
[]rune(s) decodes the UTF-8 bytes into one int32 per character, and a rune slice is mutable — so you can swap the ends inward and convert back. This is the canonical answer: no imports, no dependencies, and it works on every Go version.
Output
Prints elipmoC and 語言 oG — the Japanese survives intact because the swap moves whole runes, never half a character. The loop stops at i < j, so an odd-length string simply leaves its middle rune where it is.
2slices.Reverse (Go 1.21+)
Since Go 1.21 the standard library ships slices.Reverse, which reverses any slice in place. Hand it a []rune and the whole function collapses to three lines. It is still runes doing the work — slices.Reverse on a []byte would break UTF-8 exactly like a hand-rolled byte swap.
Output
Same output as the manual swap: elipmoC and 語言 oG. Reach for this on modern Go; keep the explicit loop if you must build against 1.20 or earlier, where the slices package doesn't exist.
3Building the result in a loop
You can also build a new string as you walk the old one. Ranging over a string yields runes (not bytes), so prepending each one reverses the text — but out = string(r) + out allocates a fresh string every iteration, which is O(n²) work. strings.Builder fixes that: one buffer, sized up front with Grow, written back to front.
Output
Both print the same answers as section 1 — elipmoC and 語言 oG. b.Grow(len(s)) takes the byte length, which is exactly what the builder needs: the reversed string has the same bytes, just reordered.
4Why reversing []byte breaks
This is the version people write first, and it is fine only if you can guarantee pure ASCII. len(s) counts bytes, indexing s[i] gives a byte, and a multi-byte character reversed byte-by-byte becomes an invalid sequence — which Go renders as �, the replacement character.
Output
The first line prints 5 bytes, 4 runes, and the range loop's indexes go 0 c, 1 a, 2 f, 3 é — note there is no index 4, because é occupies bytes 3 and 4. Compile reverses cleanly to elipmoC, but café comes back as two replacement characters followed by fac; %q shows the truth — "\xa9\xc3fac", the two bytes of é swapped into nonsense.
5Which should you use?
| Method | Unicode-safe | Allocations | Best for |
|---|---|---|---|
| []rune + swap loop | Yes | Constant | Almost everything |
| slices.Reverse([]rune) | Yes | Constant | Go 1.21+, shortest code |
| strings.Builder | Yes | Constant (with Grow) | Reversing inside a bigger build |
| out = string(r) + out | Yes | One per rune | Teaching only — O(n²) |
| []byte + swap loop | No — corrupts UTF-8 | Constant | Guaranteed-ASCII hot paths |
6Reverse the words in a sentence
Different task, same shape. strings.Fields splits on any run of whitespace and drops the empties, so you get a clean []string; swap it end-to-end and strings.Join it back. Use strings.Split(s, " ") instead only when you need to preserve empty fields.
Output
Prints day every code and fast it ship — the second line shows Fields normalising the runs of spaces and the leading/trailing padding away for free. The characters inside each word are untouched; only the word order flips.
7Where runes still aren't enough
Runes are code points, and a user-perceived character can be several of them. An accent written as a combining mark is two runes (e + U+0301), so reversing floats the accent onto the wrong letter. Flags are worse: 🇬🇧 is two regional-indicator runes, and reversing them turns the UK into Bulgaria.
Output
The pre-composed café reverses cleanly to éfac. The decomposed spelling prints "́efac" — the combining accent is now the first rune, attached to nothing. And the flag comes back as 🇧🇬. Rune reversal is the right answer for ordinary text; if you must reverse arbitrary user input exactly, segment it into grapheme clusters first with a package like github.com/rivo/uniseg, then reverse the clusters.
Frequently asked questions
Does Go have a built-in strings.Reverse function?
No. The strings package has no Reverse, so you write it yourself — convert to []rune, swap from both ends, and convert back. On Go 1.21 and later you can use slices.Reverse(runes) to do the swapping for you, but you still do the []rune conversion.
Why does reversing a Go string with []byte produce garbage?
Because a Go string is a slice of bytes, not characters, and UTF-8 uses multiple bytes for anything outside ASCII. é is two bytes and 言 is three; reversing the bytes splits those sequences apart, and the result is invalid UTF-8 that prints as the replacement character. Convert to []rune first — that decodes the bytes into whole characters.
What is the difference between a byte and a rune in Go?
A byte is an alias for uint8 — one byte of the UTF-8 encoding. A rune is an alias for int32 and holds one Unicode code point, which may be encoded as 1 to 4 bytes. len(s) counts bytes, len([]rune(s)) and utf8.RuneCountInString(s) count runes, and for i, r := range s decodes runes while reporting i as a byte offset.
How do I reverse the order of words in a Go string?
Split with strings.Fields(s), swap the resulting slice end-to-end with a two-pointer loop (or slices.Reverse), then rejoin with strings.Join(words, " "). Fields splits on any run of whitespace and discards empty entries, so extra spaces and padding are cleaned up automatically.
Is reversing runes always correct for emoji and accented text?
Not always. A rune is one code point, but a user-perceived character can be several: an accent written as a combining mark is two runes, and a flag emoji is two regional indicators, so reversing rearranges them. For ordinary text rune reversal is right; to be exact on arbitrary input, segment the string into grapheme clusters first with a package such as github.com/rivo/uniseg and reverse those.