How to Delete a Key from a Map in Go
You are managing a cache of active user sessions. A user logs out, and you need to remove their session ID from the map. In some languages, you check if the key exists, handle a "key not found" exception, and maybe return the old value. Go keeps it blunt. You call delete, and the key vanishes. If the key wasn't there, Go shrugs and moves on. No panic, no exception, no ceremony.
The delete builtin removes a key-value pair from a map. It is a function, not a method on the map type. You call it with the map as the first argument and the key as the second. The syntax is delete(m, k).
Think of a map like a physical filing cabinet. Each drawer is a bucket, and inside are folders labeled with keys. Calling delete is like pulling a folder out and shredding it. The drawer stays in the cabinet. The cabinet does not shrink. If you try to delete a folder that is not there, you just close the drawer and walk away. Nothing breaks.
Minimal example
Here is the simplest deletion. Create a map, remove a key, and print the result.
package main
import "fmt"
func main() {
// Initialize a map with three entries
scores := map[string]int{
"alice": 90,
"bob": 85,
"charlie": 78,
}
fmt.Println("Before:", scores)
// delete is a builtin function, not a method call
// It removes the key "bob" and its associated value
delete(scores, "bob")
// Calling delete on a missing key is safe
// It does nothing and does not panic
delete(scores, "dave")
fmt.Println("After:", scores)
}
The output shows bob is gone. The map still holds alice and charlie. The attempt to delete dave had no effect.
Delete versus assignment
A common trap for newcomers is confusing deletion with assignment. Setting a map entry to its zero value does not remove the key. It keeps the key in the map and changes the value to zero. This distinction matters when you iterate.
A loop over the map will still visit a key with a zero value. A deleted key vanishes from iteration entirely. The length of the map also behaves differently. len(m) decreases when you delete a key. It stays the same when you assign zero.
package main
import "fmt"
func main() {
m := map[string]int{
"x": 10,
"y": 20,
}
// Assignment to zero keeps the key in the map
// The key "x" still exists, but its value is now 0
m["x"] = 0
// len counts keys, not values
// Length is still 2 because "x" is present
fmt.Println("After zero assignment:", len(m), m)
// delete removes the key entirely
delete(m, "x")
// Length drops to 1 because "x" is gone
fmt.Println("After delete:", len(m), m)
}
If your logic depends on whether a key exists, use delete. If you just want to reset a value but keep the key as a placeholder, use assignment.
Realistic example: cleanup function
Maps are reference types. When you pass a map to a function, you pass a pointer to the underlying data structure. Deleting a key inside the function modifies the map for everyone who holds a reference to it. You do not need to return the map to reflect changes.
This pattern appears often in cleanup routines. You pass the map, filter out expired or invalid entries, and the caller sees the result immediately.
package main
import "fmt"
// removeExpired deletes keys with values less than 50
// The map is modified in place because maps are reference types
func removeExpired(data map[string]int) {
for k, v := range data {
// Check condition before deleting
// Iteration order is undefined, so this works safely
if v < 50 {
delete(data, k)
}
}
}
func main() {
cache := map[string]int{
"active": 100,
"stale": 10,
"fresh": 80,
"expired": 5,
}
fmt.Println("Before cleanup:", cache)
// Pass the map to the function
// No return value needed; the map is updated directly
removeExpired(cache)
fmt.Println("After cleanup:", cache)
}
The function iterates, checks values, and deletes keys that fail the check. The caller sees the cleaned-up map. This avoids copying the map and keeps memory usage low.
Pitfalls and edge cases
Iteration safety
Deleting keys while iterating is allowed, but the behavior is specific. The iteration order is undefined. If you delete a key you have not reached yet, the loop skips it. If you delete the current key, the loop continues to the next entry without crashing.
You cannot modify the key itself during iteration. The compiler enforces this. If you try to assign to the loop variable key, you get cannot assign to key in range. You can only delete the key or modify the value if the value is addressable.
Nil maps
Calling delete on a nil map is safe. It does nothing. This makes nil maps useful as empty maps in functions that might or might not populate data. You can call delete(nilMap, key) without a panic. The operation is a no-op.
Type mismatches
The delete builtin requires a map as the first argument and a key type that matches the map's key type. If you pass the wrong types, the compiler rejects the program.
Passing a non-map type triggers first argument to delete must be map; have int. Passing a key with the wrong type triggers cannot use 1 (untyped int constant) as string value in argument to delete. These errors catch mistakes at compile time.
No return value
delete returns nothing. You cannot capture the old value during deletion. If you need the value before it disappears, you must look it up first using the two-value assignment form.
// Lookup returns the value and a boolean indicating existence
val, ok := m[key]
if ok {
// Use val here before it is gone
delete(m, key)
}
Trying to assign the result of delete fails with cannot use delete(m, k) (value of type func(map[K]V, K)) as V value in assignment. The compiler is strict about this.
Map capacity and memory
When you delete keys, the map does not shrink. The underlying bucket array retains its capacity. This is a performance trade-off. Go maps are optimized for growth, not contraction. Frequent deletions might leave a sparse map with unused capacity.
If you delete all keys, len(m) becomes zero, but the map still holds memory. The map is not nil. It is an empty map with capacity. If you want to release the storage, assign nil to the map variable. This signals that the map is empty and allows the garbage collector to reclaim the bucket array.
// m is an empty map with capacity
delete(m, "key")
// len(m) is 0, but m is not nil
// m is now nil and storage is released
m = nil
Decision matrix
Use delete when you need to remove a key and stop it from appearing in iterations. Use assignment to zero when you want to keep the key but reset its value. Use make to clear a map when you want to wipe all entries but keep the map variable alive. Use nil assignment when you want to release the underlying storage and signal that the map is empty. Use a new map when you need to filter and keep a subset of entries without modifying the original.
Delete removes the key. Assignment hides the value. Know the difference.