What Is a Map?
A map in Erlang is a native associative collection written #{Key1 => Value1, Key2 => Value2}, introduced in Erlang/OTP 17 as a more flexible alternative to records and proplists. Unlike a record, a map carries its keys as part of the runtime value itself, so you can add, remove, or iterate over keys dynamically without ever declaring a schema, and keys can be any term, atoms, strings, tuples, or even other maps, not just compile-time-known atoms.
Cricket analogy: A live match app's stats panel can add a new field like 'DRS reviews remaining' mid-innings without redeploying the app, the same runtime flexibility a map offers by letting you add #{reviews => 2} to a map without any prior schema declaration.
Creating, Updating, and Removing Entries
Adding a fresh key or overwriting an existing one both use the => operator inside an update expression, Map2 = Map#{age => 37}, which will insert age if it wasn't present or overwrite it if it was. The stricter := operator, by contrast, only overwrites, Map#{age := 37} raises a {badkey, age} error if age is not already a key in Map, which is useful when you want to assert that you are updating, not accidentally inserting, a field.
Cricket analogy: A scorer using => to log a new bowler's figures either creates a fresh line for a debutant or updates an existing bowler's over count, while := is like insisting a substitution can only replace a player already named on the team sheet, erroring if they weren't listed.
-module(map_demo).
-export([demo/0]).
demo() ->
Ada = #{name => "Ada Lovelace", age => 36},
Older = Ada#{age => 37},
io:format("Older: ~p~n", [Older]),
case Ada of
#{name := Name, age := Age} ->
io:format("~s is ~p~n", [Name, Age])
end,
Email = maps:get(email, Ada, "no-email-on-file"),
io:format("Email: ~s~n", [Email]),
Ada2 = maps:merge(Ada, #{email => "ada@example.com", title => "Countess"}),
io:format("Keys: ~p~n", [maps:keys(Ada2)]).Pattern Matching on Maps
Maps support pattern matching directly in function heads and match expressions using the := operator: #{name := Name, age := Age} = Person extracts both fields and simultaneously asserts they are present, while a key that might be missing is safer to read with maps:get(email, Person, none) or maps:find(email, Person), which returns {ok, Value} or the atom error instead of crashing.
Cricket analogy: Selecting an XI by pattern-matching #{captain := C, wicketkeeper := WK} = Squad both extracts the named roles and asserts the squad actually has a designated captain and keeper, the same dual extract-and-assert a strict map pattern performs, while checking for an all-rounder more safely uses maps:find, which won't crash if the role is unfilled.
Map#{key := Value} raises {badkey, key} if key is not already present, reach for => when you're not sure the key exists yet, and reserve := for updates where you want a crash to signal a genuine bug rather than silently inserting a typo'd key.
Maps vs Records vs Proplists
Compared to a proplist ([{name, "Ada"}, {age, 36}]), a map offers O(1) average lookup instead of a linear scan through the list, native equality and ordering (two maps with the same key-value pairs are always ==, regardless of insertion order), and a rich standard library in the maps module covering fold, filter, merge, and iteration. Compared to a record, a map trades away compile-time field-name checking for runtime flexibility, which makes maps the better default for data with a dynamic or evolving shape, such as JSON payloads decoded from an HTTP API, while records remain preferable when you want the compiler to catch a typo'd field name at build time.
Cricket analogy: Looking up a player's strike rate in a well-indexed stats database is instant, unlike flipping through a printed scorebook page by page, the same O(1) map lookup versus proplist's linear scan; but a rigid official scorecard template still catches a mis-entered category the way a record catches a typo'd field.
Since OTP 21, maps preserve insertion order for small maps internally but you should never rely on iteration order, use maps:fold/3, maps:map/2, or maps:filter/2, which make no ordering guarantees, and if order genuinely matters, sort the result of maps:to_list/1 explicitly.
- A map is written #{Key => Value, ...} and, unlike a record, carries its keys as part of the runtime value with no compile-time schema.
- Use => to insert-or-update a key; use := to update-only, which raises {badkey, Key} if the key isn't already present.
- Pattern match with #{key := Var} = Map to extract and assert presence in one step; use maps:get/3 or maps:find/2 for safe, non-crashing optional lookups.
- Maps give O(1) average-case lookup and are always structurally comparable, unlike order-sensitive proplists.
- The maps module provides fold/3, map/2, filter/2, merge/2, keys/1, values/1, and to_list/1 for working with map data.
- Maps are the better default for dynamic or evolving data like decoded JSON; records are better when you want compile-time field-name checking.
Practice what you learned
1. What is the difference between Map#{k => v} and Map#{k := v}?
2. Which expression safely reads an optional key without risking a crash?
3. How are two maps compared for equality in Erlang?
4. Why might you prefer a map over a record for data decoded from a JSON API response?
5. What does #{name := Name, age := Age} = Person do if Person has no age key?
Was this page helpful?
You May Also Like
Records in Erlang
Records give named, compile-time-checked structure to tuples, making Erlang code more readable and less error-prone when working with structured data.
ETS Tables
ETS (Erlang Term Storage) provides fast, in-memory tables for sharing large amounts of data between processes without the overhead of message passing.
Error Handling in Erlang
Erlang handles failure through a distinctive combination of try/catch exception handling and the 'let it crash' philosophy, where supervisors, not defensive code, are the primary safety net.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics