Question
I have the following Go map:
var sessions = map[string]chan int{}
How can I delete sessions[key] from the map?
I tried:
sessions[key] = nil, false
but that does not work.
Also, in modern Go, what is the correct way to remove a map entry?
Short Answer
By the end of this page, you will understand how to remove keys from a map in Go using the built-in delete() function, what happens when a key does not exist, and how map deletion fits into common real-world coding patterns.
Concept
In Go, a map stores key-value pairs. If you want to remove an entry completely, you do not assign a special value like nil, false. Instead, you use Go's built-in delete() function.
delete(sessions, key)
This removes the entry for key from the map if it exists.
Why this matters:
- Maps are often used for lookups such as sessions, caches, counters, and configuration.
- Removing an entry is different from setting its value to a zero value.
- In many programs, whether a key exists is important.
For example, these are not the same:
sessions[key] = nil
and
delete(sessions, key)
Setting sessions[key] = nil keeps the key in the map, but stores a nil channel as its value. Deleting removes the key entirely.
This distinction matters when you check whether a key exists:
ch, ok := sessions[key]
- If the key exists,
okistrue. - If the key does not exist,
okisfalse.
So if you want the key gone, use delete().
In modern Go, the correct syntax is:
delete(sessions, key)
Mental Model
Think of a map like a set of labeled drawers.
- The key is the label on a drawer.
- The value is what is inside the drawer.
If you assign nil to a key, you are leaving the drawer in place but emptying its contents.
If you call delete(map, key), you are removing the drawer itself.
That is why checking whether the drawer exists gives different results:
- Empty drawer still exists
- Deleted drawer does not exist
Syntax and Examples
The basic syntax for removing a map entry in Go is:
delete(myMap, key)
Example 1: Delete a key from a map
package main
import "fmt"
func main() {
ages := map[string]int{
"Alice": 30,
"Bob": 25,
}
delete(ages, "Bob")
fmt.Println(ages)
}
Output:
map[Alice:30]
Example 2: Deleting from your sessions map
package main
func main() {
sessions := map[string]chan int{}
key := "user123"
sessions[key] = make(chan int)
delete(sessions, key)
}
Example 3: Check whether the key still exists
package main
import "fmt"
func main() {
sessions := map[string]chan int{}
key := "user123"
sessions[key] = make(chan int)
delete(sessions, key)
_, ok := sessions[key]
fmt.Println(ok)
}
Output:
false
Important detail
Calling delete() on a key that is not present is safe.
delete(sessions, "missing-key")
This does nothing and does not cause a panic.
Step by Step Execution
Consider this example:
package main
import "fmt"
func main() {
sessions := map[string]chan int{}
key := "abc"
sessions[key] = make(chan int)
_, before := sessions[key]
fmt.Println("Before delete:", before)
delete(sessions, key)
_, after := sessions[key]
fmt.Println("After delete:", after)
}
Step by step:
-
sessions := map[string]chan int{}- Creates an empty map.
-
key := "abc"- Stores the map key we want to use.
-
sessions[key] = make(chan int)- Adds a new entry to the map.
- Now the key
"abc"exists.
-
_, before := sessions[key]- Looks up the key.
- Since it exists,
beforebecomestrue.
-
delete(sessions, key)- Removes the key-value pair from the map.
-
_, after := sessions[key]- Looks up the same key again.
- Since it was deleted,
afterbecomesfalse.
Output:
Before delete: true
After delete: false
This shows the difference between a present key and a deleted key clearly.
Real World Use Cases
Map deletion appears in many real programs.
Session management
Your original example uses sessions. When a user logs out or a session expires, you remove it:
delete(sessions, sessionID)
Caches
If cached data becomes outdated, remove it so fresh data can be loaded later.
delete(cache, productID)
Counters and temporary state
If you track request counts or temporary job state, you may remove entries when work is complete.
Feature flags or configuration overrides
If a specific override should no longer apply, deleting the key restores default behavior.
In-memory registries
Maps are often used to track connected clients, workers, background tasks, or subscriptions. When one disconnects or finishes, its entry is deleted.
Real Codebase Usage
In real Go codebases, delete() is commonly used with a few practical patterns.
Cleanup after work finishes
func removeSession(sessions map[string]chan int, id string) {
delete(sessions, id)
}
This is common in request lifecycle cleanup and resource tracking.
Guard clause before using a value
Developers often check whether a key exists before operating on it:
ch, ok := sessions[id]
if !ok {
return
}
close(ch)
delete(sessions, id)
This avoids using a missing entry.
Validation and invalidation
Maps are often used for memoization or caches. When source data changes, entries are invalidated with delete().
func invalidateUser(cache map[string]string, userID string) {
delete(cache, userID)
}
Error handling and cleanup
If part of a process fails after temporary state is stored in a map, developers may delete the entry during rollback or cleanup.
Paired with mutexes in concurrent programs
Regular Go maps are not safe for concurrent reads and writes. In real applications, map deletion is often protected with a mutex:
package main
import "sync"
type SessionStore struct {
mu sync.Mutex
sessions map[string]chan int
}
func (s *SessionStore) Delete(id string) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.sessions, id)
}
This pattern is common in servers and background systems.
Common Mistakes
1. Setting a value to nil instead of deleting the key
Broken idea:
sessions[key] = nil
This does not remove the key. It only stores a nil value.
Use this instead:
delete(sessions, key)
2. Expecting delete() to return a value
Broken code:
ok := delete(sessions, key)
delete() does not return anything.
Correct:
delete(sessions, key)
3. Forgetting to check whether a key exists
If you need to know whether the key was present, use the two-value map lookup:
_, ok := sessions[key]
if ok {
delete(sessions, key)
}
This check is optional for deletion, but useful if your logic depends on existence.
4. Confusing zero values with missing keys
For some value types, the zero value can look like a valid value.
counts := map[string]int{}
fmt.Println(counts["missing"])
This prints 0, but that does not mean the key exists.
Use:
value, ok := counts["missing"]
5. Concurrent map access without protection
Broken pattern:
go delete(sessions, key)
go sessions["other"] = make(chan int)
Regular maps are not safe for unsynchronized concurrent access.
Use a mutex or sync.Map when needed.
6. Deleting from a nil map without understanding behavior
Deleting from a nil map is allowed and does nothing:
var sessions map[string]chan int
delete(sessions, "x")
But writing to a nil map will panic:
sessions["x"] = make(chan int) // panic
Comparisons
| Operation | Meaning | Key still exists? | Example |
|---|---|---|---|
delete(m, key) | Removes the entry completely | No | delete(sessions, key) |
m[key] = nil | Stores nil as the value | Yes | sessions[key] = nil |
value, ok := m[key] | Reads a value and checks existence | Depends on ok | ch, ok := sessions[key] |
delete() vs assigning a zero value
| Approach | What it does | When to use it |
|---|---|---|
delete(m, key) | Removes the key from the map | When the entry should no longer exist |
m[key] = 0 or m[key] = "" or m[key] = nil | Keeps the key but changes its stored value | When the key should remain but its value should reset |
Regular map vs sync.Map
| Type | Best for | Notes |
|---|---|---|
map[K]V | Most normal cases | Fast and simple, but not safe for concurrent access without locking |
sync.Map | Some concurrent workloads | Useful in specific shared-access patterns, but less common for everyday code |
Cheat Sheet
Remove a key
delete(m, key)
Example
sessions := map[string]chan int{}
delete(sessions, "user123")
Check whether a key exists
value, ok := m[key]
ok == truemeans the key existsok == falsemeans the key does not exist
Important rules
delete()removes the map entry completelydelete()returns nothing- Deleting a missing key is safe
- Deleting from a nil map is safe
- Writing to a nil map panics
- Setting
m[key] = nilis not the same as deleting the key
Common pattern
if ch, ok := sessions[id]; ok {
close(ch)
delete(sessions, id)
}
Remember
- Delete key:
delete(m, key) - Keep key but reset value: assign zero value or
nil - Need existence check: use
value, ok := m[key]
FAQ
How do you delete a key from a map in Go?
Use the built-in function:
delete(myMap, key)
Does delete() fail if the key is missing?
No. If the key does not exist, delete() does nothing.
Is m[key] = nil the same as deleting a map entry?
No. That keeps the key in the map and stores a nil value. Deleting removes the key entirely.
Can I delete from a nil map in Go?
Yes. It is safe and does nothing.
Does delete() return whether the key existed?
No. If you need that information, check first using:
_, ok := m[key]
Can I delete map entries while ranging over a map?
Yes, Go allows deleting entries during map iteration. Still, you should keep the logic clear and simple.
Are Go maps safe for concurrent delete operations?
Not by default. Use synchronization such as sync.Mutex, or consider sync.Map for suitable cases.
Mini Project
Description
Build a small in-memory session manager in Go. This project demonstrates how to store sessions in a map, look them up, and remove them correctly when a session ends. It is practical because many web servers, background workers, and real-time systems track active items in maps.
Goal
Create a session store that can add, check, remove, and list active sessions using a Go map.
Requirements
- Create a map where the key is a session ID string and the value is a
chan int. - Add at least two sessions to the map.
- Write a function to check whether a session exists.
- Write a function to delete a session by ID.
- Print the session list before and after deletion.
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.