maxminddb
Library for reading MaxMind DB format used by GeoIP2 and GeoLite2
0.30.0
28M downloads/mo
#1739 most downloaded on crates.io
oschwald/maxminddb-rust
What this package is like to depend on
Last release 1 months ago
19 Jul 2026
Release timing varies
gaps range from 2 weeks to 1.8 years
Some releases are documented
notes for 34 of 57 stable releases
Nothing withdrawn
no release was ever pulled
12 years old
58 releases · first in 2014
8 releases in the last 12 months
see the full history below
Release timeline
58 releases · Nov 2014 to Jul 2026Releases
latest 58-
0.30.019 Jul 2026Release notes
Open source →- Added
deserialize_any_with_raw_strings()for Serde-based format adapters
to validate MMDB strings while constructing another runtime's native string
type, avoiding duplicate UTF-8 validation without unsafe Rust. Adapters
remain responsible for strict UTF-8 validation. - Fixed network iteration on cyclic or over-deep corrupt search trees so it
returns an error instead of looping indefinitely. - Fixed
decode_path()error rendering for extreme negative indexes and
reduced path traversal header parsing. - Removed decoder logging checks from hot deserialization paths.
- Fixed
verify()to validate shared data-section pointer targets once, reject
pointer cycles, invalid scalar encodings, and impossible container sizes.
Release notes
Open source →- Added
deserialize_any_with_raw_strings()for Serde-based format adapters to validate MMDB strings while constructing another runtime's native string type, avoiding duplicate UTF-8 validation without unsafe Rust. Adapters remain responsible for strict UTF-8 validation. - Fixed network iteration on cyclic or over-deep corrupt search trees so it returns an error instead of looping indefinitely.
- Fixed
decode_path()error rendering for extreme negative indexes and reduced path traversal header parsing. - Removed decoder logging checks from hot deserialization paths.
- Fixed
verify()to validate shared data-section pointer targets once, reject pointer cycles, invalid scalar encodings, and impossible container sizes.
- Added
-
0.29.028 Jun 2026Release notes
Open source →- Breaking:
Metadata::build_time()now returns
Result<SystemTime, MaxMindDbError>instead of panicking on
unrepresentable timestamps, and databases whosebuild_epochcannot be
represented asSystemTimeare rejected as invalid during open and verify. - Breaking:
Reader::metadatais now private. UseReader::metadata()to
access validated metadata by shared reference. - Breaking: Opening a database now rejects unsupported major format versions,
unsupported IP versions, and zero-node search trees. Minor format versions
are still accepted for forward compatibility. - Fixed:
within()andnetworks()now handle IPv6 databases without an
IPv4 subtree without reading terminal data nodes as tree nodes or
panicking while formatting low IPv6 networks. - Fixed: Skipping ignored or unknown fields now enforces data-section
bounds and the maximum nesting depth instead of accepting truncated
values or overflowing the stack on deeply nested corrupt data. - Internal: Added focused benchmarks for network iteration and serde
unknown-field skipping, plus metadata build-time conversion, to guard
performance-sensitive fixes. - Documentation: Fixed intra-doc links so docs build with warnings denied,
and added a CI check to keep them passing.
Release notes
Open source →- Breaking:
Metadata::build_time()now returnsResult<SystemTime, MaxMindDbError>instead of panicking on unrepresentable timestamps, and databases whosebuild_epochcannot be represented asSystemTimeare rejected as invalid during open and verify. - Breaking:
Reader::metadatais now private. UseReader::metadata()to access validated metadata by shared reference. - Breaking: Opening a database now rejects unsupported major format versions, unsupported IP versions, and zero-node search trees. Minor format versions are still accepted for forward compatibility.
- Fixed:
within()andnetworks()now handle IPv6 databases without an IPv4 subtree without reading terminal data nodes as tree nodes or panicking while formatting low IPv6 networks. - Fixed: Skipping ignored or unknown fields now enforces data-section bounds and the maximum nesting depth instead of accepting truncated values or overflowing the stack on deeply nested corrupt data.
- Internal: Added focused benchmarks for network iteration and serde unknown-field skipping, plus metadata build-time conversion, to guard performance-sensitive fixes.
- Documentation: Fixed intra-doc links so docs build with warnings denied, and added a CI check to keep them passing.
- Breaking:
-
0.28.126 Apr 2026Release notes
Open source →- Fixed: Databases with an impossible declared search tree size are now
rejected during open/verify instead of causing runaway allocation
during validation. - Fixed:
within()now rejects IPv6 CIDRs on IPv4-only databases instead
of yielding unrelated networks. - Fixed: Verification now rejects truncated scalar/string payloads instead
of skipping past them and reporting the database as valid. - Fixed:
LookupResult::network()now uses the reader's measured IPv4
subtree depth instead of assuming it always begins at bit 96.
Release notes
Open source →- Fixed: Databases with an impossible declared search tree size are now rejected during open/verify instead of causing runaway allocation during validation.
- Fixed:
within()now rejects IPv6 CIDRs on IPv4-only databases instead of yielding unrelated networks. - Fixed: Verification now rejects truncated scalar/string payloads instead of skipping past them and reporting the database as valid.
- Fixed:
LookupResult::network()now uses the reader's measured IPv4 subtree depth instead of assuming it always begins at bit 96.
- Fixed: Databases with an impossible declared search tree size are now
-
0.28.025 Apr 2026Release notes
Open source →- Performance improvement: Faster search-tree traversal by dispatching
on the database's record size to monomorphized node readers, replacing
per-step branching on the record size. - Performance improvement: Direct deserialization of scalars, sequences,
maps, and structs through dedicated fast paths instead of routing
throughdeserialize_any. - Performance improvement: IPv4 and IPv6 lookups dispatch to dedicated
paths, avoiding per-call address-kind checks on the hot path. - Behavior change: Deserializing a database array into a tuple or
tuple struct now returns a decoding error when the lengths do not
match. Previously the mismatch was silently ignored. - Fixed: A corrupt data pointer that would underflow during resolution
now returns anInvalidDatabaseerror instead of panicking.
Release notes
Open source →- Performance improvement: Faster search-tree traversal by dispatching on the database's record size to monomorphized node readers, replacing per-step branching on the record size.
- Performance improvement: Direct deserialization of scalars, sequences,
maps, and structs through dedicated fast paths instead of routing
through
deserialize_any. - Performance improvement: IPv4 and IPv6 lookups dispatch to dedicated paths, avoiding per-call address-kind checks on the hot path.
- Behavior change: Deserializing a database array into a tuple or tuple struct now returns a decoding error when the lengths do not match. Previously the mismatch was silently ignored.
- Fixed: A corrupt data pointer that would underflow during resolution
now returns an
InvalidDatabaseerror instead of panicking.
- Performance improvement: Faster search-tree traversal by dispatching
-
0.27.316 Feb 2026Release notes
Open source →- Removed the
release_max_level_infofeature from thelogdependency, as
libraries should not set a global release log-level cap. Pull request by
monosans. GitHub #110.
Release notes
Open source →- Removed the
release_max_level_infofeature from thelogdependency, as libraries should not set a global release log-level cap. Pull request by monosans. GitHub #110.
- Removed the
-
0.27.214 Feb 2026Release notes
Open source →- Performance improvement: Faster lookups and record decoding in common paths,
including control-byte header parsing and integer decoding. - Performance improvement: Faster string decoding for ASCII-only values by
using a dedicated ASCII fast path. - Performance improvement: Reduced release-build overhead by compiling out
debug/trace logging calls. - Fixed: Truncated or corrupt data in control-byte headers now returns a
decoding error instead of panicking.
Release notes
Open source →- Performance improvement: Faster lookups and record decoding in common paths, including control-byte header parsing and integer decoding.
- Performance improvement: Faster string decoding for ASCII-only values by using a dedicated ASCII fast path.
- Performance improvement: Reduced release-build overhead by compiling out debug/trace logging calls.
- Fixed: Truncated or corrupt data in control-byte headers now returns a decoding error instead of panicking.
- Performance improvement: Faster lookups and record decoding in common paths,
-
0.27.118 Dec 2025Release notes
Open source →- Performance improvement: Skipped UTF-8 validation for map keys during
deserialization. This significantly speeds up full record decoding by
treating keys as raw bytes when matching against struct fields. - Performance improvement: Optimized tree traversal by reducing bounds checks
during node reading.
Release notes
Open source →- Performance improvement: Skipped UTF-8 validation for map keys during deserialization. This significantly speeds up full record decoding by treating keys as raw bytes when matching against struct fields.
- Performance improvement: Optimized tree traversal by reducing bounds checks during node reading.
- Performance improvement: Skipped UTF-8 validation for map keys during
-
0.27.028 Nov 2025Release notes
Open source →This release includes significant API changes. See UPGRADING.md
for migration guidance.Breaking Changes
Lookup API
lookup()now returnsLookupResultinstead ofOption<T>. The new API
enables lazy decoding - data is only deserialized when explicitly requested.lookup_prefix()has been removed. Uselookup(ip)?.network()instead.
Iteration API
within()now requires a secondWithinOptionsparameter. Use
Default::default()for the previous behavior.Withiniterator now yieldsLookupResultinstead ofWithinItem<T>.
GeoIP2 Structs
- The
namesfields now use aNamesstruct instead ofBTreeMap<&str, &str>.
Access names directly via language fields (e.g.,names.english). - Nested struct fields (
city,country,location, etc.) are now
non-optional withDefault, simplifying access patterns. - Removed
is_anonymous_proxyandis_satellite_providerfromTraits.
These fields are no longer present in MaxMind databases.
Error Types
InvalidDatabaseandDecodingvariants now use structured fields instead
of a single string. Pattern matching must be updated.- New
InvalidInputvariant for user input errors (e.g., IPv6 lookup in
IPv4-only database).
Memory Mapping
Reader::open_mmapis nowunsafe. The caller must ensure the database
file is not modified or truncated while theReaderexists. This fixes a
soundness issue. Reported by paolobarbolini. GitHub #86.
Added
LookupResulttype with lazy decoding support:has_data()- Check if data exists for this IPnetwork()- Get the network containing the IPoffset()- Get data offset for caching/deduplicationdecode()- Deserialize full recorddecode_path()- Selectively decode specific fields by path
PathElementenum andpath!macro for navigating nested structures.WithinOptionsto control network iteration behavior:include_aliased_networks()- Include IPv4 via IPv6 aliasesinclude_networks_without_data()- Include networks without data recordsskip_empty_values()- Skip empty maps/arrays
networks()method for iterating over all networks in the database.verify()method for comprehensive database validation.Metadata::build_time()to convertbuild_epochtoSystemTime.PartialEqandEqimplementations forMetadataandWithinOptions.
Changed
- Error messages now include byte offsets when available.
decode_path()errors include path context showing where navigation failed.- Added recursion depth limit (512) matching libmaxminddb and Go reader.
- Serde deserializer improvements: size hints,
is_human_readable()returns
false,deserialize_ignored_any, anddeserialize_enumsupport. MaxMindDbErroris now#[non_exhaustive].
Release notes
Open source →This release includes significant API changes. See UPGRADING.md for migration guidance.
Breaking Changes
Lookup API
lookup()now returnsLookupResultinstead ofOption<T>. The new API enables lazy decoding - data is only deserialized when explicitly requested.lookup_prefix()has been removed. Uselookup(ip)?.network()instead.
Iteration API
within()now requires a secondWithinOptionsparameter. UseDefault::default()for the previous behavior.Withiniterator now yieldsLookupResultinstead ofWithinItem<T>.
GeoIP2 Structs
- The
namesfields now use aNamesstruct instead ofBTreeMap<&str, &str>. Access names directly via language fields (e.g.,names.english). - Nested struct fields (
city,country,location, etc.) are now non-optional withDefault, simplifying access patterns. - Removed
is_anonymous_proxyandis_satellite_providerfromTraits. These fields are no longer present in MaxMind databases.
Error Types
InvalidDatabaseandDecodingvariants now use structured fields instead of a single string. Pattern matching must be updated.- New
InvalidInputvariant for user input errors (e.g., IPv6 lookup in IPv4-only database).
Memory Mapping
Reader::open_mmapis nowunsafe. The caller must ensure the database file is not modified or truncated while theReaderexists. This fixes a soundness issue. Reported by paolobarbolini. GitHub #86.
Added
LookupResulttype with lazy decoding support:has_data()- Check if data exists for this IPnetwork()- Get the network containing the IPoffset()- Get data offset for caching/deduplicationdecode()- Deserialize full recorddecode_path()- Selectively decode specific fields by path
PathElementenum andpath!macro for navigating nested structures.WithinOptionsto control network iteration behavior:include_aliased_networks()- Include IPv4 via IPv6 aliasesinclude_networks_without_data()- Include networks without data recordsskip_empty_values()- Skip empty maps/arrays
networks()method for iterating over all networks in the database.verify()method for comprehensive database validation.Metadata::build_time()to convertbuild_epochtoSystemTime.PartialEqandEqimplementations forMetadataandWithinOptions.
Changed
- Error messages now include byte offsets when available.
decode_path()errors include path context showing where navigation failed.- Added recursion depth limit (512) matching libmaxminddb and Go reader.
- Serde deserializer improvements: size hints,
is_human_readable()returns false,deserialize_ignored_any, anddeserialize_enumsupport. MaxMindDbErroris now#[non_exhaustive].
-
0.26.028 Mar 2025Release notes
Open source →- BREAKING CHANGE: The
lookupandlookup_prefixmethods now return
Ok(None)orOk((None, prefix_len))respectively when an IP address is
valid but not found in the database (or has no associated data record),
instead of returning anErr(MaxMindDbError::AddressNotFoundError).
Code previously matching onAddressNotFoundErrormust be updated to
handle theOk(None)/Ok((None, prefix_len))variants. - BREAKING CHANGE: The
MaxMindDBErrorenum has been renamed
MaxMindDbErrorand variants have been renamed and refactored. For
example,IoErroris nowIo,InvalidDatabaseErroris now
InvalidDatabase,DecodingErroris nowDecoding,
InvalidNetworkErroris nowInvalidNetwork. TheMapErrorvariant has
been replaced byMmap(under themmapfeature flag). Code explicitly
matching on the old variant names must be updated. - BREAKING CHANGE:
MaxMindDbErrorno longer implementsPartialEq.
This is because underlying error types likestd::io::Error(now
wrapped by theIoandMmapvariants) do not implementPartialEq.
Code comparing errors directly using==orassert_eq!must be
updated, typically by usingmatches!or by matching on the error
kind and potentially its contents. - Refactored
MaxMindDbErrorhandling using thethiserrorcrate.
Variants likeIo,Mmap, andInvalidNetworknow directly wrap
the underlying error types (std::io::Error,ipnetwork::IpNetworkError). - Errors wrapping underlying types (
Io,Mmap,InvalidNetwork) now
correctly implementstd::error::Error::source(), allowing inspection
of the original cause. - The
Displayimplementation forMaxMindDbErrorhas been refined to
generally show only the specific error details, often including the
message from the source error, rather than prefixing with the variant
name. lookup_prefixnow returns the prefix length of the entry even when the
value is not found.- Fixed an internal bounds checking error when resolving data pointers.
The previous logic could cause a panic on a corrupt database.
Release notes
Open source →- BREAKING CHANGE: The
lookupandlookup_prefixmethods now returnOk(None)orOk((None, prefix_len))respectively when an IP address is valid but not found in the database (or has no associated data record), instead of returning anErr(MaxMindDbError::AddressNotFoundError). Code previously matching onAddressNotFoundErrormust be updated to handle theOk(None)/Ok((None, prefix_len))variants. - BREAKING CHANGE: The
MaxMindDBErrorenum has been renamedMaxMindDbErrorand variants have been renamed and refactored. For example,IoErroris nowIo,InvalidDatabaseErroris nowInvalidDatabase,DecodingErroris nowDecoding,InvalidNetworkErroris nowInvalidNetwork. TheMapErrorvariant has been replaced byMmap(under themmapfeature flag). Code explicitly matching on the old variant names must be updated. - BREAKING CHANGE:
MaxMindDbErrorno longer implementsPartialEq. This is because underlying error types likestd::io::Error(now wrapped by theIoandMmapvariants) do not implementPartialEq. Code comparing errors directly using==orassert_eq!must be updated, typically by usingmatches!or by matching on the error kind and potentially its contents. - Refactored
MaxMindDbErrorhandling using thethiserrorcrate. Variants likeIo,Mmap, andInvalidNetworknow directly wrap the underlying error types (std::io::Error,ipnetwork::IpNetworkError). - Errors wrapping underlying types (
Io,Mmap,InvalidNetwork) now correctly implementstd::error::Error::source(), allowing inspection of the original cause. - The
Displayimplementation forMaxMindDbErrorhas been refined to generally show only the specific error details, often including the message from the source error, rather than prefixing with the variant name. lookup_prefixnow returns the prefix length of the entry even when the value is not found.- Fixed an internal bounds checking error when resolving data pointers. The previous logic could cause a panic on a corrupt database.
- BREAKING CHANGE: The
-
0.25.016 Feb 2025Release notes
Open source →- Serde will now skip serialization of the GeoIP2 struct fields
whenOptionis none. Pull request by Stefan Sundin. GitHub #79. SerializeandClonewere added to theMetadatastruct. Pull
request by Stefan Sundin. GitHub #80.- Added feature to use
simdutf8as a faster alternative when
unsafe-str-decodeis too risky. Pull request by Jakub Onderka.
GitHub #88. - Minor internal refactoring and performance improvements.
Release notes
Open source →- Serde will now skip serialization of the GeoIP2 struct fields when
Optionis none. Pull request by Stefan Sundin. GitHub #79. SerializeandClonewere added to theMetadatastruct. Pull request by Stefan Sundin. GitHub #80.- Added feature to use
simdutf8as a faster alternative whenunsafe-str-decodeis too risky. Pull request by Jakub Onderka. GitHub #88. - Minor internal refactoring and performance improvements.
- Serde will now skip serialization of the GeoIP2 struct fields
-
0.24.010 Jan 2024Release notes
Open source →- Added the
is_anycastfield to theTraitsstruct. Pull request by Skye. GitHub #73.
- Added the
-
0.23.003 Apr 2022Release notes
Open source →- Added
lookup_prefixto return the prefix length for the network associated with the IP address. Pull request by Marek Vavruša. GitHub #26.
- Added
-
0.22.023 Mar 2022Release notes
Open source →- A
withinmethod has been added to the reader to allow iterating over all records in the database. Pull request by Ross McFarland. Github #50. - Database structs in
maxminddb::geoip2have been updated. Most noticeably, anEnterprisestruct has been added and themodelmodule has been replaced bycityandcountrymodules. Also, several missing fields have been added. Mmapis now re-exported for convenience. Pull request by zhuhaow. GitHub #54.- Upgraded memmap2 dependency.
- A
-
0.21.020 Jul 2021Release notes
Open source →- Reduce the amount of code generated by shrinking generic methods. Pull request by Markus Westerlind. GitHub #49.
-
0.20.011 Jul 2021Release notes
Open source →- Use
try_intowhen decoding floating point values. Pull request by Sebastian Mayr. GitHub #47.
- Use
-
0.19.025 Jun 2021Release notes
Open source →- Switch from
memmaptomemmap2. Pull request by Gleb Pomykalov. GitHub #46.
- Switch from
-
0.18.029 May 2021Release notes
Open source →- The
memchrcrate is now used to improve the performance of finding the metadata start. Pull request by Markus Westerlind. GitHub #44.
- The
-
0.17.329 May 2021Release notes
Open source →- Correct handling of pointers in the database metadata section. This bug
caused the latest GeoIP2 ISP database from MaxMind to fail to load with an
InvalidDatabaseErrordue to an invalid data type. Reported by Marwes-Imperva. GitHub #45.
- Correct handling of pointers in the database metadata section. This bug
caused the latest GeoIP2 ISP database from MaxMind to fail to load with an
-
0.17.212 Feb 2021 -
0.17.104 Jan 2021Release notes
Open source →- Restore compatibility with targets that don't support 128-bit integers. Pull request by Filip. GitHub #41.
-
0.17.012 Dec 2020Release notes
Open source →- Unsigned 128-bit integers are now decoded to a
u128rather than a[u8]. Pull request by moschroe. GitHub #40.
- Unsigned 128-bit integers are now decoded to a
-
0.16.005 Dec 2020Release notes
Open source →- This release includes major performance improvements and code cleanup. Pull request by Sebastian Mayr. GitHub #37.
-
0.15.010 Oct 2020Release notes
Open source →- Remove crate options leftover from before Rust 1.0. In particular, this crate
no longer specifies
crate_type. This should allow you to compile it withpanic = "abort". Reported by ye2020. GitHub #33.
- Remove crate options leftover from before Rust 1.0. In particular, this crate
no longer specifies
-
0.14.007 Jun 2020Release notes
Open source →- BREAKING CHANGE: All Strings in the
geoip2structs are not returned as references. This was done to provide a significant performance improvement when ownership is not needed. Pull request by Matthew Wynn. GitHub #31. - A new opt-in feature,
unsafe-str-decode, has been added that will skip UTF-8 validation when decoding strings. You should only use this when you trust that the MaxMind DB is valid and contains valid UTF-8 strings. This provides a modest performance improvement. Pull request by Matthew Wynn. GitHub #31. - Many other internal improvements to reduce the number of allocations.
- BREAKING CHANGE: All Strings in the
-
0.13.021 Jan 2019Release notes
Open source →- Missing models for
DensityIncome,Domain, andAsnwere added and the missingis_in_european_unionfield was added to theCountrymodel. Pull request by Sebastian Nadorp. GitHub #19. - More details are now included in the
Displayimplementation forMaxMindDBError. Pull request by Mike Cooper. GitHub #20.
- Missing models for
-
0.12.009 Dec 2018Release notes
Open source →Reader::openhas been removed. You should useReader::open_readfileorReader::open_mmap. Pull request by kpcyrd. GitHub #17 & #18.Reader::open_readfileno longer depends onunsafe. Pull request by kpcyrd. GitHub #17 & #18.
-
0.11.013 Nov 2018Release notes
Open source →- An optional
mmapcfg feature flag has been added. When set,openwill use thememmapcrate to memory map the database file rather than reading it from file. In addition toopen,open_readfileandopen_mmapare available. PR by moschroe. GitHub #16. Reader::opennow takes anAsRef<Path>. Also, #16.Reader::from_bufallows using an existing buffer instead of specifying a database file. PR by kpcyrd. GitHub #15.
- An optional
-
0.10.008 Aug 2018Release notes
Open source →- Derive
Serializefor GeoIP2 models. Pull request by Bryan Gilbert. GitHub #11.
- Derive
-
0.9.017 Feb 2018 -
0.8.102 Jul 2017 -
0.8.029 Jun 2017Release notes
Open source →- API CHANGE: Switch to Serde for deserialization. Data structures being
deserialized to must implement the
Deserializetrait. Pull request by Wesley Moore. GitHub #5.
- API CHANGE: Switch to Serde for deserialization. Data structures being
deserialized to must implement the
-
0.7.216 Apr 2017 -
0.7.114 Nov 2016 -
0.7.015 May 2016Release notes
Open source →- API CHANGE:
lookuptakes anIpAddragain instead of aSocketAddr. We previously switched toSocketAddrafterIpAddrhad been deprecated, but it has since been re-added.
- API CHANGE:
-
0.6.224 Jan 2016Nothing published for this version
-
0.6.111 Dec 2015Nothing published for this version
-
0.6.026 Oct 2015Nothing published for this version
-
0.5.505 Sep 2015Nothing published for this version
-
0.5.409 Aug 2015Nothing published for this version
-
0.5.320 May 2015Nothing published for this version
-
0.5.216 May 2015Nothing published for this version
-
0.5.120 Apr 2015Nothing published for this version
-
0.5.019 Apr 2015Nothing published for this version
-
0.4.019 Apr 2015Nothing published for this version
-
0.3.004 Apr 2015Nothing published for this version
-
0.2.127 Mar 2015Nothing published for this version
-
0.2.024 Mar 2015Nothing published for this version
-
0.1.921 Mar 2015Nothing published for this version
-
0.1.828 Feb 2015Nothing published for this version
-
0.1.722 Feb 2015Nothing published for this version
-
0.1.614 Feb 2015Nothing published for this version
-
0.1.531 Jan 2015Nothing published for this version
-
0.1.424 Jan 2015Nothing published for this version
-
0.1.310 Jan 2015Nothing published for this version
-
0.1.204 Jan 2015Nothing published for this version
-
0.1.126 Dec 2014Nothing published for this version
-
0.1.022 Nov 2014Nothing published for this version
-
0.1.0-pre22 Nov 2014 pre-releaseNothing published for this version