Question
In Go, what is the difference between the = and := operators, and when should each one be used?
They both appear to assign values to variables, so it is not immediately clear how they differ in practice.
Short Answer
By the end of this page, you will understand that = is used to assign a new value to an existing variable, while := is used for short variable declaration, which both declares and initializes variables. You will also see where each can be used, how scope affects them, and which beginner mistakes to avoid.
Concept
In Go, = and := are related, but they do different jobs.
=means assign a value to a variable that already exists.:=means declare a new variable and give it an initial value at the same time.
This distinction matters because Go is a statically typed language. Variables must be declared before they can be used. The := syntax is a convenient shortcut that lets Go infer the variable's type from the value on the right side.
= assignment
Use = when the variable has already been declared.
var age int
age = 30
You can also assign a new value later:
age = 31
:= short variable declaration
Use := when you want to create a variable and initialize it in one step.
age := 30
Go infers that age is an int.
Why this matters
This is important in real Go programs because:
- it affects scope
- it affects readability
- it prevents use of undeclared variables
- it helps Go infer types cleanly
A very common source of bugs is accidentally using := inside a smaller scope and creating a new variable instead of updating an existing one.
Mental Model
Think of variables like labeled storage boxes.
:=is like creating a new box, putting a label on it, and placing something inside.=is like opening an existing box and replacing what is inside.
If the box does not exist yet, you cannot use =.
If the box already exists, using := may create a different box in a smaller area instead of reusing the original one.
Syntax and Examples
Core syntax
Declare and initialize with :=
name := "Alice"
count := 10
isAdmin := true
Use this inside functions when you want a quick local variable declaration.
Declare first, assign later with =
var name string
name = "Alice"
Reassign an existing variable with =
score := 100
score = 120
Multiple variables with :=
x, y := 1, 2
Multiple assignment with =
x = 3
y = 4
Or:
x, y = 3, 4
Important rule about :=
:= can only be used when at least one variable on the left side is new.
x := 1
x, y := 2, 3 // valid because y is new
But this is invalid:
x := 1
x := 2 // invalid in the same scope: no new variables
Example
package main
import "fmt"
func main() {
language := "Go"
fmt.Println(language)
language = "Golang"
fmt.Println(language)
}
What happens here
language := "Go"declares a new variable namedlanguagelanguage = "Golang"updates the existing variable- both lines store values, but only the first line creates the variable
Step by Step Execution
Consider this example:
package main
import "fmt"
func main() {
count := 5
fmt.Println(count)
count = 8
fmt.Println(count)
}
Step-by-step
-
count := 5- Go creates a new variable named
count - Go infers its type as
int - The value
5is stored in it
- Go creates a new variable named
-
fmt.Println(count)- The current value of
countis printed - Output:
5
- The current value of
-
count = 8- No new variable is created
- The existing
countvariable is updated to8
-
fmt.Println(count)- The updated value is printed
- Output:
8
Scope example
package main
import "fmt"
func main() {
value := 10
if true {
value := 20
fmt.Println("inside:", value)
}
fmt.Println("outside:", value)
}
What prints
inside: 20
outside: 10
Inside the if block, value := 20 creates a new local variable instead of changing the outer value. This is called shadowing.
Real World Use Cases
Where := is commonly used
Local variables inside functions
userID := 42
name := "Sam"
This is the most common style for short local setup code.
Receiving function results
result, err := doWork()
This is extremely common in Go, especially with error handling.
Loop and temporary values
for i := 0; i < 5; i++ {
fmt.Println(i)
}
Where = is commonly used
Updating state
total := 0
total = total + 5
Assigning after declaration
var configPath string
configPath = "/etc/app.conf"
Reusing existing variables
var err error
result, err = doWork()
This is useful when the variable already exists and you want to update it instead of declaring a new one.
Real Codebase Usage
In real Go codebases, developers usually follow a few common patterns.
1. Prefer := for short local declarations
Inside functions, := is often the default for variables that are first introduced close to where they are used.
file, err := os.Open("data.txt")
This keeps code short and readable.
2. Use = when updating existing variables
count := 0
count = count + 1
This makes it clear that the variable already exists and is being changed.
3. Use var plus = when zero value or wider scope is useful
var err error
var data []byte
data, err = os.ReadFile("config.json")
This is common when a variable must be used across several branches or later in the function.
4. Be careful with error shadowing
A common real-world bug happens when a developer writes := and accidentally creates a new err variable in an inner scope.
result, err := firstStep()
if err != nil {
return err
}
if true {
result, err := secondStep()
_ = result
if err != nil {
return err
}
}
The inner err is different from the outer one. This is sometimes fine, but sometimes confusing. Many teams prefer avoiding unnecessary shadowing for readability.
5. Guard clause pattern
data, err := loadData()
if err != nil {
return err
}
This style appears throughout Go programs. := is used to declare data and err once, then if err != nil handles failure immediately.
Common Mistakes
1. Using = before declaring a variable
Broken code:
name = "Alice"
Why it fails:
namedoes not exist yet- Go requires variables to be declared before assignment
Fix:
name := "Alice"
Or:
var name string
name = "Alice"
2. Using := for an existing variable in the same scope
Broken code:
age := 20
age := 21
Why it fails:
- the second line does not introduce any new variable
:=requires at least one new variable on the left side
Fix:
age := 20
age = 21
3. Accidental shadowing inside a block
Broken or confusing code:
total := 100
if true {
total := 50
fmt.Println(total)
}
fmt.Println(total)
This prints:
50
100
Why it happens:
- the inner
total := 50creates a new variable - it does not update the outer
total
Fix if you want to update the outer variable:
total := 100
if true {
total = 50
}
fmt.Println(total)
4. Trying to use := at package level
Broken code:
package main
message := "hello"
Why it fails:
- short variable declaration is only allowed inside functions
Fix:
package main
var message = "hello"
5. Confusing declaration with reassignment in multiple assignment
x := 1
x, y := 2, 3
This is valid because y is new.
But this is not:
x := 1
y := 2
x, y := 3, 4
Fix:
x := 1
y := 2
x, y = 3, 4
Comparisons
| Concept | := | = |
|---|---|---|
| Main purpose | Declare and initialize | Assign to an existing variable |
| Creates a new variable | Yes | No |
| Can update existing variable | Only if at least one left-side variable is new | Yes |
| Type inference | Yes | No by itself |
| Allowed at package level | No | Yes, after declaration |
| Common use | Local variables inside functions | Reassignment and updates |
var vs :=
| Syntax | Meaning | Typical use |
|---|---|---|
var x int | Declare variable with explicit type | When you want a specific type or zero value |
var x = 10 | Declare with inferred type | Package or function scope |
x := 10 | Short declaration with inferred type | Local variables inside functions |
Quick rule
- Use
:=when introducing a new local variable. - Use
=when changing an existing variable.
Cheat Sheet
Quick reference
Use := when
- you are declaring a new variable
- you are inside a function
- you want Go to infer the type
name := "Go"
count := 10
result, err := doWork()
Use = when
- the variable already exists
- you want to change its value
- you declared it earlier with
varor:=
count = 20
err = nil
x, y = 1, 2
Rules to remember
:=declares and initializes=only assigns:=works only inside functions:=needs at least one new variable on the left side=cannot be used with undeclared variables:=can accidentally shadow outer variables
Common patterns
value := 10
value = 11
var name string
name = "Alice"
data, err := load()
if err != nil {
return err
}
Common error signs
no new variables on left side of :=undefined: variableName- unexpected shadowing in inner blocks
FAQ
Can I use := everywhere in Go?
No. := can only be used inside functions. At package level, use var.
Is := just a shorter version of var?
It is a short declaration form for local variables. It both declares the variable and initializes it, with type inference.
Can I use = to create a variable?
No. = only assigns to a variable that already exists.
Why does Go say "no new variables on left side of :="?
Because := requires at least one variable on the left side to be newly declared in the current scope.
What is variable shadowing in Go?
Shadowing happens when := creates a new variable inside an inner scope with the same name as an outer variable.
Should I prefer := or var in Go?
Inside functions, := is often preferred for short local variables. Use var when you need explicit types, zero values, or package-level declarations.
Can := and = both appear to assign values?
Yes, both place values into variables, but only := creates a new variable. = only updates an existing one.
Mini Project
Description
Build a small Go program that tracks a user's score. This project helps you practice when to declare variables with :=, when to update them with =, and how to avoid accidentally creating a second variable in a nested block.
Goal
Create a program that declares a score, updates it several times, and prints the final result correctly.
Requirements
- Declare at least one variable using
:=insidemain - Update an existing variable using
= - Use an
ifblock and avoid accidental shadowing - Print the score before and after updates
Keep learning
Related questions
Are Go Maps Passed by Value or Reference?
Learn Go map parameter and return semantics: maps are passed by value, while copies share underlying data. Know when map pointers are useful.
Authentication for Go REST APIs: Sessions, Tokens, and Middleware
Learn practical authentication patterns for Go REST APIs, including password hashing, server sessions, bearer tokens, middleware, and security rules.
Automatic Build Versioning in Go: Embed Incrementing Build Numbers
Learn how to add automatic build versioning in Go using linker flags, build metadata, CI counters, and Git-based version values.