New Way:

From Go 1.10 there is a strings.Builder type, please take a look at this answer for more detail.

Old Way:

Use the bytes package. It has a Buffer type which implements io.Writer.

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var buffer bytes.Buffer

    for i := 0; i < 1000; i++ {
        buffer.WriteString("a")
    }

    fmt.Println(buffer.String())
}

This does it in O(n) time.

Answer from marketer on Stack Overflow
Top answer
1 of 16
1095

New Way:

From Go 1.10 there is a strings.Builder type, please take a look at this answer for more detail.

Old Way:

Use the bytes package. It has a Buffer type which implements io.Writer.

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var buffer bytes.Buffer

    for i := 0; i < 1000; i++ {
        buffer.WriteString("a")
    }

    fmt.Println(buffer.String())
}

This does it in O(n) time.

2 of 16
644

In Go 1.10+ there is strings.Builder, here.

A Builder is used to efficiently build a string using Write methods. It minimizes memory copying. The zero value is ready to use.


Example

It's almost the same with bytes.Buffer.

package main

import (
    "strings"
    "fmt"
)

func main() {
    // ZERO-VALUE:
    //
    // It's ready to use from the get-go.
    // You don't need to initialize it.
    var sb strings.Builder

    for i := 0; i < 1000; i++ {
        sb.WriteString("a")
    }

    fmt.Println(sb.String())
}

Click to see this on the playground.


Supported Interfaces

strings.Builder's methods are being implemented with the existing interfaces in mind so that you can switch to the new Builder type easily in your code.

Method Signature Interface Description
Grow(int) bytes.Buffer Grows the buffer's capacity by the specified amount. See bytes.Buffer#Grow for more information.
Len() int bytes.Buffer Returns the number of bytes in the buffer. See bytes.Buffer#Len for more information.
Reset() bytes.Buffer Resets the buffer to be empty. See bytes.Buffer#Reset for more information.
String() string fmt.Stringer Returns the contents of the buffer as a string. See fmt.Stringer for more information.
Write([]byte) (int, error) io.Writer Writes the given bytes to the buffer. See io.Writer for more information.
WriteByte(byte) error io.ByteWriter Writes the given byte to the buffer. See io.ByteWriter for more information.
WriteRune(rune) (int, error) bufio.Writer or bytes.Buffer Writes the given rune to the buffer. See bufio.Writer#WriteRune or bytes.Buffer#WriteRune for more information.
WriteString(string) (int, error) io.stringWriter Writes the given string to the buffer. See io.stringWriter for more information.

Differences from bytes.Buffer

  • It can only grow or reset.
  • It has a copyCheck mechanism built-in that prevents accidentally copying it. In bytes.Buffer, one can access the underlying bytes like this: (*Buffer).Bytes(). strings.Builder prevents this problem. Sometimes, this is not a problem, though, and is desired instead. For example: For the peeking behavior when the bytes are passed to an io.Reader etc.
  • bytes.Buffer.Reset() rewinds and reuses the underlying buffer whereas the strings.Builder.Reset() does not, it detaches the buffer.

Note

  • Do not copy a strings.Builder value as it caches the underlying data.
  • If you want to share a strings.Builder value, use a pointer to it.

Check out its source code for more details, here.

🌐
Sentry
sentry.io › sentry answers › go › concatenating strings in go
Concatenating strings in Go | Sentry
October 15, 2024 - The simplest way to combine strings, especially when concatenating just a few values, is to use the + operator:
🌐
Reddit
reddit.com › r/golang › efficient string concatenation
r/golang on Reddit: efficient string concatenation
June 11, 2024 -
NOTE:  After discussion with this awesome subreddit, I realize I'm asking the wrong question.  I don't need a string builder.  I'm optmizing just for the sake of optimizing, which is wrong.  So will just stick to + operator. 

Thank you all for the feedback !

I'm aware of strings.Builder but here is my confusion.

I need to use some string variables. My first thought was to do this:

var s strings.Builder
name := "john"
s.WriteString("hello " + name)
fmt.Println(s.String())

Dumb question, is still wrong to use + ? Or should I do this:

var s strings.Builder
name := "john"
s.WriteString("hello ")
s.WriteString(name)
fmt.Println(s.String())

EDIT1: adding bechmarks.

code:

concat_test.go

package main

import (
	"strings"
	"testing"
)

func BenchmarkConcatAndWrite(b *testing.B) {
	var s strings.Builder
	name := "john"
        b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		s.Reset()
		s.WriteString("hello " + name)
	}
}

func BenchmarkSeparateWrites(b *testing.B) {
	var s strings.Builder
	name := "john"
        b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		s.Reset()
		s.WriteString("hello ")
		s.WriteString(name)
	}
}

results:

go test -bench=.
goos: darwin
goarch: amd64
pkg: test
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkConcatAndWrite-12    	25422900	        44.04 ns/op	      16 B/op	       1 allocs/op
BenchmarkSeparateWrites-12    	26773579	        44.37 ns/op	      24 B/op	       2 allocs/op
PASS
ok  	test	2.518s

EDIT2: posting actual code and updated benchmark.

concat.go

package concat

import (
	"fmt"
	"strings"
)

type Metadata struct {
	NumReplica int `json:"num_replica"`
}

type IndexData struct {
	BucketId    string   `json:"bucket_id"`
	Condition   string   `json:"condition"`
	DatastoreId string   `json:"datastore_id"`
	Id          string   `json:"id"`
	IndexKey    []string `json:"index_key"`
	IsPrimary   bool     `json:"is_primary"`
	KeyspaceId  string   `json:"keyspace_id"`
	Metadata    Metadata `json:"metadata"`
	Name        string   `json:"name"`
	NamespaceId string   `json:"namespace_id"`
	Partition   string   `json:"partition"`
	ScopeId     string   `json:"scope_id"`
	State       string   `json:"state"`
	Using       string   `json:"using"`
}

func ConcatAndWrite(data IndexData) string {
	var indexDefinition strings.Builder

	switch data.IsPrimary {

	case false:
		indexDefinition.WriteString("CREATE INDEX " + data.Name + " ON ")
		indexDefinition.WriteString(data.BucketId + "." + data.ScopeId + "." + data.KeyspaceId)
		indexDefinition.WriteString("(")

		for i, ik := range data.IndexKey {
			if i > 0 {
				indexDefinition.WriteString(",")
			}
			indexDefinition.WriteString(ik)
		}
		indexDefinition.WriteString(")")

		if data.Partition != "" {
			indexDefinition.WriteString(" PARTITION BY " + data.Partition)
		}

		if data.Condition != "" {
			indexDefinition.WriteString(" WHERE " + data.Condition)
		}

	case true:
		indexDefinition.WriteString("CREATE PRIMARY INDEX ")

		if data.Name != "#primary" {
			indexDefinition.WriteString(data.Name + " ")
		}

		indexDefinition.WriteString("ON " + data.BucketId + "." + data.ScopeId + "." + data.KeyspaceId)
	}

	if data.Metadata.NumReplica > 0 {
		replicas := fmt.Sprint(data.Metadata.NumReplica)
		indexDefinition.WriteString(" WITH {\"num_replica\":" + replicas + "\"}")
	}

	return indexDefinition.String()
}

func NoConcat(data IndexData) string {
	var indexDefinition strings.Builder

	switch data.IsPrimary {

	case false:
		indexDefinition.WriteString("CREATE INDEX ")
		indexDefinition.WriteString(data.Name)
		indexDefinition.WriteString(" ON ")
		indexDefinition.WriteString(data.BucketId)
		indexDefinition.WriteString(".")
		indexDefinition.WriteString(data.ScopeId)
		indexDefinition.WriteString(".")
		indexDefinition.WriteString(data.KeyspaceId)
		indexDefinition.WriteString("(")

		for i, ik := range data.IndexKey {
			if i > 0 {
				indexDefinition.WriteString(",")
			}
			indexDefinition.WriteString(ik)
		}
		indexDefinition.WriteString(")")

		if data.Partition != "" {
			indexDefinition.WriteString(" PARTITION BY ")
			indexDefinition.WriteString( data.Partition)
		}

		if data.Condition != "" {
			indexDefinition.WriteString(" WHERE ")
			indexDefinition.WriteString(data.Condition)
		}

	case true:
		indexDefinition.WriteString("CREATE PRIMARY INDEX ")

		if data.Name != "#primary" {
			indexDefinition.WriteString(data.Name)
			indexDefinition.WriteString( " ")
		}

		indexDefinition.WriteString("ON ")
		indexDefinition.WriteString(data.BucketId)
		indexDefinition.WriteString(".")
		indexDefinition.WriteString(data.ScopeId)
		indexDefinition.WriteString(".")
		indexDefinition.WriteString(data.KeyspaceId)
	}

	if data.Metadata.NumReplica > 0 {
		replicas := fmt.Sprint(data.Metadata.NumReplica)
		indexDefinition.WriteString(" WITH {\"num_replica\":")
		indexDefinition.WriteString(replicas )
		indexDefinition.WriteString("\"}")
	}

	return indexDefinition.String()
}

func ConcatPlusOperator(data IndexData) string {
	var indexDefinition string

	switch data.IsPrimary {
	case false:
		indexKeys := strings.Join(data.IndexKey, ",")
		indexDefinition += fmt.Sprintf("CREATE INDEX %s ON %s.%s.%s(%s)", data.Name, data.BucketId, data.ScopeId, data.KeyspaceId, indexKeys)

		if data.Partition != "" {
			indexDefinition += fmt.Sprintf(" PARTITION BY %s",data.Partition)
		}

		if data.Condition != "" {
			indexDefinition += fmt.Sprintf(" WHERE %s", data.Condition) 
		}

	case true:
		indexDefinition = "CREATE PRIMARY INDEX "

		if data.Name != "#primary" {
			indexDefinition += fmt.Sprintf("%s ", data.Name)
		}

		indexDefinition += fmt.Sprintf("ON %s.%s.%s", data.BucketId, data.ScopeId, data.KeyspaceId)
	}
	
	if data.Metadata.NumReplica > 0 {
		indexDefinition += fmt.Sprintf(" WITH {\"num_replica\": %d \"}", data.Metadata.NumReplica)
	}

	return indexDefinition
}

concat_test.go

package concat

import (
	"testing"
)

func BenchmarkConcatAndWrite(b *testing.B) {
	m := Metadata{NumReplica: 2}

	data := IndexData{
		BucketId:    "jobs",
		Condition:   "(`id` = 2)",
		DatastoreId: "http://127.0.0.1:8091",
		Id:          "a607ef2e22e0b436",
		IndexKey:    []string{"country", "name", "id"},
		KeyspaceId:  "c2",
		Metadata:    m,
		Name:        "idx3",
		NamespaceId: "default",
		Partition:   "HASH((meta().`id`))",
		ScopeId:     "s1",
		State:       "online",
		Using:       "gsi",
	}

	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		ConcatAndWrite(data)
	}
}

func BenchmarkNoConcat(b *testing.B) {
	m := Metadata{NumReplica: 2}

	data := IndexData{
		BucketId:    "jobs",
		Condition:   "(`id` = 2)",
		DatastoreId: "http://127.0.0.1:8091",
		Id:          "a607ef2e22e0b436",
		IndexKey:    []string{"country", "name", "id"},
		KeyspaceId:  "c2",
		Metadata:    m,
		Name:        "idx3",
		NamespaceId: "default",
		Partition:   "HASH((meta().`id`))",
		ScopeId:     "s1",
		State:       "online",
		Using:       "gsi",
	}

	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		NoConcat(data)
	}
}

func BenchmarkPlusOperator(b *testing.B) {
	m := Metadata{NumReplica: 2}

	data := IndexData{
		BucketId:    "jobs",
		Condition:   "(`id` = 2)",
		DatastoreId: "http://127.0.0.1:8091",
		Id:          "a607ef2e22e0b436",
		IndexKey:    []string{"country", "name", "id"},
		KeyspaceId:  "c2",
		Metadata:    m,
		Name:        "idx3",
		NamespaceId: "default",
		Partition:   "HASH((meta().`id`))",
		ScopeId:     "s1",
		State:       "online",
		Using:       "gsi",
	}

	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		ConcatPlusOperator(data)
	}
}

benchmarks:

go test -bench=.
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkConcatAndWrite-12    	 2932362	       404.1 ns/op	     408 B/op	       5 allocs/op
BenchmarkNoConcat-12          	 4595264	       258.0 ns/op	     240 B/op	       4 allocs/op
BenchmarkPlusOperator-12      	 1343035	       890.4 ns/op	     616 B/op	      15 allocs/op
PASS
ok  	_/Users/hiteshwalia/go/src/local/test/concat	5.262s
🌐
YourBasic
yourbasic.org › golang › build-append-concatenate-strings-efficiently
Efficient string concatenation [full guide] · YourBasic Go
yourbasic.org/golang · Clean and simple string building (fmt) High-performance string concatenation (stringbuilder) Before Go 1.10 (bytebuffer) For simple cases where performance is a non-issue, fmt.Sprintf is your friend. It’s clean, simple and fairly efficient.
🌐
Golang
golang.company › blog › perform-string-concatenation-in-go
7 Ways to Perform String Concatenation in Go
August 18, 2022 - This is another simple method to concatenate a string in Golang. What this function will do is that it will combine different elements in the slice of a string to create a new string.
🌐
DEV Community
dev.to › schadokar › the-fastest-way-to-concatenate-strings-in-golang-5mf
The fastest way to concatenate strings in Golang - DEV Community
April 30, 2024 - ... BenchmarkPlusOperator-11 115559880 ... ns/op BenchmarkStringsBuilderOperator-11 45078675 26.17 ns/op · The + operator is the fastest way to concatenate strings and fmt.Sprintf is the slowest....
🌐
Calhoun
calhoun.io › concatenating-and-building-strings-in-go
Concatenating and Building Strings in Go 1.10+ - Calhoun.io
Go 1.10 introduced the new strings.Builder type, which can be used to efficiently and easily build or concatenate strings. In this post we explore some of the ways to use the type as well as why it implementing the io.Writer interface makes it an incredibly powerful tool.
Find elsewhere
🌐
CodeSignal
codesignal.com › learn › courses › getting-started-with-go-programming-language › lessons › string-manipulation-in-go-mastering-concatenation-operations
String Manipulation in Go: Mastering Concatenation ...
Let's look at how: Here, the '+' ... this technique in some of our earlier fmt.Println statements. ... In Go, the '+' operator only allows the same data types specifically when concatenation is intended....
🌐
TutorialsPoint
tutorialspoint.com › go › go_string_concatenation.htm
Go - String Concatenation
In Golang, string concatenation involves joining two or more strings together to form a single string. we can concatenate the strings using '+' operator and strings.Join() function.
🌐
Programming Tips
programming-tips.info › concatenate_string_literal › go › en › index.html
Concatenate strings in Golang - Programming Tips
Concatenate strings in Golang Concatenate string literals (string enclosed in double quotes). To concatenate strings simply, use + operator. However, if strings are concatenated by + operator, new string object is generated. If you use bytes.Buffer, string is stored in buffer.
🌐
Freshman Tech
freshman.tech › snippets › go › string-concatenation
5 Ways to Perform String Concatenation in Go - Freshman.tech
October 6, 2022 - There are several possible methods for doing this in Go, each with their own unique trade-offs which will be considered in this article. The easiest way to concatenate strings in Go is by using the concatenation operator (+).
🌐
Medium
medium.com › @arjun.devb25 › optimizing-string-merging-in-go-a-tale-of-two-solutions-6e6ccfef4c7f
Optimizing String Merging in Go: A Tale of Two Solutions | by Arjun Singh | Medium
January 1, 2025 - Byte Slice for Accumulation: Instead of concatenating strings, we use a []byte slice to collect the characters. Efficient Appending: The append() function adds elements to the byte slice efficiently, without creating new strings on each operation. Conversion to String: After the loop finishes, we convert the byte slice to a string using string(res). Memory Allocation: In Go, slices are more memory-efficient than strings because slices don’t create new copies of the underlying array on each modification.
🌐
Bill Glover
billglover.me › 2019 › 03 › 13 › learn-go-by-concatenating-strings
Learn Go: by Concatenating Strings - Bill Glover
September 28, 2025 - Benchmarking shows that there are 99 memory allocations when joining 100 strings. My working theory is that this is one memory allocation per concatenation operation. We can validate this by looking at the code. ... // concatstrings implements a Go string concatenation x+y+z+... // The operands are passed in the slice a.
🌐
LabEx
labex.io › tutorials › go-how-to-join-string-values-419742
How to join string values | LabEx
Go provides a rich set of built-in functions and methods for manipulating strings. Some common operations include: Concatenation: Use the + operator or the strings.Join() function to combine strings.
🌐
Golang Docs
golangdocs.com › home › 7 ways to concatenate strings in golang
7 Ways to Concatenate Strings in Golang - Golang Docs
January 28, 2020 - The strings can be appended to one another by using the += operator. It is the same as above. But a slightly shorter way of concatenating. It appends the right side to the string it is operated on. So, it essentially appends string.
🌐
Scaler
scaler.com › home › topics › golang › how to concatenate strings in golang?
How to Concatenate Strings in GoLang? - Scaler Topics
May 4, 2023 - The strings are immutable in the Go language and are an arbitrary chain of bytes that are encoded with UTF-8. The process of adding or joining two or more strings together to make a new string is termed concatenation.
🌐
TutorialEdge.net
tutorialedge.net › home › "golang development" › "concatenate strings in go"
Concatenate Strings in Go | TutorialEdge.net
July 15, 2019 - In this code snippet, we are going to look at how you can use the strings.Builder type to efficiently concatenate strings in Go.
🌐
Risor
risor.io › docs › comparisons › golang-string-concat
String Concatenation - Risor
In the example below, the concatenation of the two strings s1 and s2 and a space in between is stored in result and then printed. ... package main import "fmt" func main() { s1 := "thanks" s2 := "for all the fish" result := s1 + " " + s2 fmt.Println(result) } ... Try this in the Go playground here (opens in a new tab).
🌐
ZetCode
zetcode.com › golang › add-string
Adding Strings in Go
April 11, 2024 - In Go, a string is a read-only slice of bytes. ... The + and the += operators provide the easiest way of concatenating strings.