glom review
glom 25.12.0 is a Python mini-language for reading, reshaping, validating, and sometimes mutating nested objects. A dotted string follows a path, a dictionary describes output fields, a one-item list maps over input, and a tuple pipes one transformation into the next. Named specifiers such as `Coalesce`, `Match`, `Iter`, `Assign`, and `Delete` add fallback, validation, streaming, and mutation. The current release is maintenance-only, adding Python 3.13 and 3.14 tests and test fixes. Our Python 3.12 install was pure Python and small, but the distribution has no `py.typed` marker and does not declare a Python requirement in its metadata.
glom 25.12.0 installed in 0.5 seconds, used 2 MB, imported in 0.51 seconds, and produced 0 pip-audit findings in our sandbox. It earns its place when nested transformations repeat across a codebase; direct Python remains clearer for short, local lookups.
We installed it
| Install | ✓ · 0.5s | 4 packages on disk · 2 MB |
| Import | ✓ | import glom in 0.51s · pure Python |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does glom install cleanly?
Yes. In a fresh container with an empty cache, pip install glom finished in 0.5s, leaving 4 packages and 2 MB on disk. pip-audit reported no known vulnerabilities.
What does glom need to run?
Python 3.x, and nothing compiled: it is pure Python. In our run import glom succeeded in 0.51s.
glom or jmespath: which should you use?
jmespath: Use it for read-only JSON queries expressed in a language with implementations beyond Python. glom 25.12.0 installed in 0.5 seconds, used 2 MB, imported in 0.51 seconds, and produced 0 pip-audit findings in our sandbox.
When should you not use glom?
A couple of subscripts and one comprehension already tell the story. glom's container rules and specifier classes add a language that maintainers must learn.
Use it if
- Several endpoints need the same nested payload reshaped into a stable output dictionary.
- Deep lookup failures should identify the exact path segment instead of ending as a generic KeyError or TypeError.
- A transformation combines mapping, filtering, fallback, reduction, or validation and a named spec is easier to test than repeated loops.
- Developers want to prototype short JSON transformations with a command-line tool before placing the spec in Python code.
- A couple of subscripts and one comprehension already tell the story. glom's container rules and specifier classes add a language that maintainers must learn.
- Specs arrive from users or another untrusted service. A spec may call Python functions, access methods, or mutate objects, so evaluating it is code execution.
- The validation contract must work in JavaScript, Go, or an OpenAPI client. `Match` is Python behavior and does not emit a portable schema.
- You need to walk every node of an arbitrary recursive object tree. The glom FAQ points general tree traversal to `remap` rather than claiming that job.
- The transformation sits in a proven CPU hot path. Spec dispatch, path parsing, scope handling, and richer exceptions cost more than direct indexing.
Setup reality
We installed glom 25.12.0 in 0.5 seconds inside a fresh Python 3.12 Bookworm sandbox. The environment ended with 4 packages taking 2 MB. The distribution reports 5 direct dependencies, is pure Python, and has no py.typed marker. Its metadata does not specify a Python floor or a usable license value. import glom worked in 0.51 seconds, and pip-audit found 0 known vulnerabilities.
There are no credentials, services, or configuration files. Installation adds both the Python module and a glom command. The CLI consumes JSON by default; TOML and YAML depend on the documented format support and extras. A path query is pleasant at the shell, but nested tuple and dictionary specs quickly become a quoting exercise. Put longer transformations in a Python module where they can be named and tested.
The learning cost appears on the first real spec. Strings with dots mean traversal, one-item lists map, dictionaries construct output, tuples form a pipeline, and callables run on the current target. To read a literal key containing a dot, use T['a.b'] or Path. Wildcards also carry glom meaning. A broad default or Coalesce can quietly convert a malformed required field into an ordinary-looking result, so attach fallbacks only to optional data.
Most glom() calls create a new result, but assign() and delete() modify the supplied object. Copy shared input before mutation. Call, Invoke, arbitrary callables, attribute access, and custom spec types make trusted-code ownership a security boundary. The 25.12.0 changelog lists test coverage work for Python 3.13 and 3.14, while package metadata still leaves requires-python blank. Test the exact interpreter versions in your own build rather than inferring support from metadata.
Patterns
Read a nested field read-deep-path
from glom import glom
payload = {'customer': {'address': {'city': 'Pune'}}}
city = glom(payload, 'customer.address.city')A missing segment raises `PathAccessError` with its position in the 3-part path, which is more specific than a later TypeError.
Try two email locations fallback-between-paths
from glom import Coalesce, glom
email = glom(
payload,
Coalesce('contact.work_email', 'contact.personal_email', default=None),
)`Coalesce` checks candidates in order. Its default should represent an optional field, since it also hides path failures.
Build a smaller output dictionary reshape-record
from glom import Coalesce, glom
spec = {
'customer_id': 'customer.id',
'name': 'customer.profile.name',
'postcode': Coalesce('customer.address.postcode', default=None),
}
summary = glom(payload, spec)Every value spec runs against the original payload. Dictionary keys become the output field names.
Convert nested invoice rows map-and-convert-list
from glom import glom
spec = ('invoices', [{
'id': 'number',
'amount': ('amount_paise', lambda value: value / 100),
}])
rows = glom(payload, spec)A list containing 1 spec maps it over each item. Tuple elements execute as sequential stages.
Read a literal key containing a dot access-dotted-key
from glom import T, glom
data = {'invoice.total': 1250, 'tax_rate': 0.18}
result = glom(data, {
'subtotal': T['invoice.total'],
'gross': T['invoice.total'] * (1 + T['tax_rate']),
})The string `'invoice.total'` would mean a 2-segment path. `T[...]` treats it as one literal mapping key.
Drop inactive records with SKIP filter-mapped-values
from glom import SKIP, glom
active_ids = glom(
users,
[lambda user: user['id'] if user.get('active') else SKIP],
)`SKIP` removes the list element. Returning `None` would preserve an element whose value is null.
Match required field types validate-record-list
from glom import Match, glom
record_shape = Match([{'id': int, 'email': str, object: object}])
validated = glom(records, record_shape)The `object: object` pair allows extra fields. A mismatch raises a `MatchError` subtype rather than returning false.
Change a value in place assign-nested-field
from glom import assign
customer = {'profile': {'status': 'trial'}}
assign(customer, 'profile.status', 'paid')`assign()` mutates `customer`. Make a copy first when another caller relies on the original object.
Remove temporary data delete-nested-field
from glom import delete
customer = {'profile': {'name': 'Asha', 'debug': True}}
delete(customer, 'profile.debug')Deletion happens in place. A failed traversal or removal raises `PathDeleteError`.
Combine child lists flatten-one-level
from glom import Flatten, glom
items = glom([[1, 2], [], [3], [4, 5]], Flatten())
assert items == [1, 2, 3, 4, 5]`Flatten()` removes 1 iterable layer. It is not a recursive walk over an unknown tree.
Process an iterator lazily stream-filter-results
from glom import Iter, T, glom
spec = Iter().filter(T['active']).map(T['id'])
active_ids = list(glom(users, spec))`Iter` defers work until iteration. Converting to `list` consumes the full source and materializes every result.
Check a path from the shell query-json-cli
glom --scalar 'customer.address.city' '{"customer":{"address":{"city":"Pune"}}}'The `--scalar` flag prints a single value without JSON string quoting. It was added in 24.11.0 and remains in 25.12.0.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| jmespath | PyPI | Use it for read-only JSON queries expressed in a language with implementations beyond Python. |
| dpath | PyPI | Use it for glob-like get, search, set, and merge operations over dictionaries without glom's full spec model. |
| BeneDict | PyPI | Use it when attribute and key-path access on dictionary-like objects is the main need rather than declarative reshaping. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

