---
name: meta-pattern
description: The dynamic-attributes (Meta) pattern used by User and Participant in the Mediknode/Unified codebase. Use when reading or writing dynamic/custom attributes on users or participants, importing user/participant data, or touching UserMeta/ParticipantMeta.
---

# Meta pattern (dynamic attributes)

`User` and `Participant` carry arbitrary key/value attributes via `hasMany(Meta)` — `UserMeta` and `ParticipantMeta`.

## How it works
- Pending metas are **collected** on the model instance, then **bulk-saved** in the model's `booted()` hook (on `created`/`saved`). Look for `$pendingMetas` on the model (e.g. `Participant::$pendingMetas`).
- Do **not** insert metas one row at a time in a loop — set them through the model's meta API so they batch correctly and trigger audit logging once.

## When importing (very common — see [[excel-io]])
- Route user/participant custom fields through the Meta pattern, not raw `UserMeta::create()` in a tight loop.
- `ImportUserMetas` exists for bulk meta import — read it before writing similar code.

## Gotchas
- Reading a meta that doesn't exist returns null — guard with defaults.
- Metas are audited via observers like everything else on User/Participant.

See also: [[project-conventions]], [[audit-observers]].
