---
title: "Modifiers"
description: "The .forge field modifiers — + auto-generate, & unique, ^ indexed, and ? nullable — with placement and type rules."
purpose: "reference"
---
Modifiers are sigils on a field's type. Three are **prefix** modifiers (`+`, `&`,
`^`) placed before the type name; one is the **nullable** modifier (`?`) placed after.
| Symbol | Name | Position | Meaning | Valid on |
|--------|------|----------|---------|----------|
| `+` | auto-generate | prefix | Fill on create (`uuid`/`timestamp` today; integer is a marker) | `u32`, `u64`, `uuid`, `timestamp` only |
| `&` | unique | prefix | Value must be unique (enforced) | any type |
| `^` | indexed | prefix | Build an index for fast lookups | any type |
| `?` | nullable | postfix (or prefix) | Value may be absent | any type |
## `+` — auto-generate
`+` marks a field ForgeDB fills for you. On **create** (`db.create_<model>`, and the REST
`POST /api/<model>` that routes through it), an omitted or nil `+uuid` gets a fresh
`Uuid::new_v4()` and an omitted or zero `+timestamp` gets the current time, so callers
never supply them. Valid **only on** `u32`, `u64`, `uuid`, and `timestamp`:
```forge
id: +uuid // fresh UUID on create when omitted/nil
seq: +u64 // primary-key marker — NOT yet auto-incremented (see below)
created_at: +timestamp // current time on create when omitted/zero
```
<Callout type="warning" title="`+` is type-restricted">
`+` on any other type — e.g. `name: +string` — is a fatal parse error. Only the four
generatable types above are allowed.
</Callout>
<Callout type="warning" title="Integer `+` is a marker, not yet auto-incremented">
`+u32`/`+u64` currently only *mark* the primary-key / auto field — the generator does not
yet synthesize a value for them, so a create must still supply the integer id. Auto-increment
for integer keys (a monotonic, restart-safe, reuse-free counter) is planned; it is
deliberately not shipped as a subtly-wrong version that could reuse a deleted id. `+uuid` and
`+timestamp` are fully synthesized today. See
[issue #187](https://github.com/hoodiecollin/forgedb/issues/187).
</Callout>
## `&` — unique
`&` marks a column whose values must be unique across all rows. Uniqueness is **enforced**:
on `insert`/`update` the generated code probes the field's index and rejects a duplicate
(HTTP 409). Applies to any type.
```forge
email: &string @email
slug: &string
```
`&` builds an index too, so a unique field is also fast to look up.
## `^` — indexed
`^` builds a secondary index on the field for fast `find_by_*` lookups and for
index-served REST filters. Applies to any indexable type (not `json`).
```forge
slug: ^string
views: ^u64
status: ^OrderStatus
```
Combine `&` and `^` freely; since `&` already indexes, `^&` mainly documents intent.
See [indexes & projections](/docs/schema/indexes-and-projections/) for hash-vs-ordered
index behavior.
## Combining prefix modifiers
Any combination of `+`, `&`, `^` is allowed, in any order, all before the type —
subject to the rule that `+` is valid only on `u32`/`u64`/`uuid`/`timestamp`:
```forge
id: +&^uuid // auto-gen + unique + indexed (auto-gen needs an eligible type)
email: ^&string @email // indexed + unique
```
## `?` — nullable
`?` makes a field optional (may be absent / `NULL`). It is a **postfix** modifier, placed
after the type, and this is the idiomatic form. A prefix form also parses:
```forge
bio: string? // nullable string (idiomatic)
age: i32? // nullable int
avatar: ?string // prefix form — also parses
published_at: timestamp?
```
`?` composes with the prefix modifiers:
```forge
external_id: +uuid? // auto-generate and nullable
```
On a relation, prefix `?` declares an **optional foreign key**
(`editor: ?User`). See [relations](/docs/schema/relations/).
<Callout type="note" title="Nullable storage keeps absent distinct from zero">
A nullable fixed-width field carries a 1-byte presence tag, so `None` and a stored `0`
(or `Value::Null`, or an empty string) round-trip as different values.
</Callout>