Boolean field
f.boolean() is a true/false field backed by a Postgres boolean column, with a z.boolean() schema and equality / null filtering built in.
f.boolean() stores a true / false value. It produces a Postgres boolean column, derives a z.boolean() schema, and exposes equality and null filter operators on the typed where clause. It takes no arguments and has no type-specific methods, you shape it entirely with the shared modifiers every field has.
Prerequisites: read Fields first, this page covers only the
booleantype. Thefproxy, the chain-modifier model, and shared modifiers like.required()/.default()/.localized()are taught there.
What it does
- Stores a true/false value, a Postgres
booleancolumn, no precision or length to configure. - Validates as a boolean, the derived schema is
z.boolean(), so a non-boolean insert is a validation error. - Filters with boolean operators,
eq,ne,isNull,isNotNull, all typed againstboolean. - Renders a toggle / checkbox in the admin form.
Quick start
Use f.boolean() inside a .fields() callback. There is no constructor argument; chain the shared modifiers to refine it.
import { collection } from "#questpie/factories";
export const posts = collection("posts").fields(({ f }) => ({
published: f.boolean().label("Published").default(false).required(), // NOT NULL, defaults to false
featured: f.boolean(), // nullable boolean
}));That gives posts a published column typed boolean on read, required on insert with a false default, and a nullable featured column, filterable with the operators below, with no schema or migration written by hand.
Constructor argument
f.boolean() takes no arguments. It always produces a boolean column with a z.boolean() schema.
| Call | Column | Schema |
|---|---|---|
f.boolean() | boolean | z.boolean() |
Chained methods
f.boolean() has no type-specific methods, it returns a plain Field, not a FieldWithMethods wrapper, because there is nothing boolean-specific to refine. Shape it with the shared modifiers every field carries (.required(), .default(), .label(), .description(), .localized(), .array(), .access(), .hooks(), …).
collection("settings").fields(({ f }) => ({
// Common pattern: a non-null flag with an explicit default.
emailNotifications: f
.boolean()
.label("Email notifications")
.default(true)
.required(),
}));`.default(value)` is type-checked against `boolean`
.default() is type-constrained to the field's data type, exactly like Drizzle, f.boolean().default("yes") won't compile. Passing a .default(...) also makes the field optional on insert. For a column-level SQL default instead of a JS value, use .drizzle((c) => c.default(sql`true`)).
Filtering, operators
boolean uses the boolean operator set (booleanOps), so every boolean field is filterable with these in a where clause. The operand is typed boolean.
| Operator | Operand | Matches |
|---|---|---|
eq / ne | boolean | Exact equal / not equal. |
isNull / isNotNull | boolean | Column is (not) null. Pass true to assert the condition, false to invert it. |
// Only published rows
const { docs } = await app.collections.posts.find({
where: { published: { eq: true } },
});
// Rows where `featured` was never set
const { docs: unset } = await app.collections.posts.find({
where: { featured: { isNull: true } },
});There are no gt / lt / in style operators, for a tri-state value (true / false / unknown), keep the column nullable and filter isNull / isNotNull alongside eq.
For the full query language, combining field filters with AND / OR / NOT, pagination, and orderBy, see the query reference.
When to use it
f.boolean(), any two-state flag:published,featured,isActive,acceptedTerms, feature toggles, opt-ins.- Pair it with
.default(false)/.default(true)+.required()for a non-null flag that never reads back asnull, usually what you want for a toggle. - Leave it nullable (no
.required()) when "not yet decided" is a meaningful third state, then filter withisNull/isNotNull. - For a fixed set of more than two states (e.g.
draft/review/live), reach forf.select()instead of stacking booleans.
Multiple values
Chain .array() to store a list of booleans in a single jsonb column, and bound the list length with .minItems(n) / .maxItems(n). This is a shared modifier, not boolean-specific:
answers: f.boolean().array().maxItems(20), // boolean[] stored as jsonbTypeScript
A boolean field contributes a boolean to the generated row, insert, and where types, no annotation needed. After questpie generate, pull the shapes off the collection or the app types:
type Post = typeof posts.$infer.select;
// ^? { id: string; published: boolean; featured: boolean | null; ... }import type { CollectionDoc, CollectionWhere } from "#questpie/types";
type Post = CollectionDoc<"posts">; // { published: boolean; ... }
type PostFilter = CollectionWhere<"posts">; // { published?: { eq?: boolean; ... } }.required() makes the field non-null and required on insert; without it the column is nullable and the insert field optional. .default(false) makes the input optional and is type-checked against boolean. See Fields → inferred types for how modifiers flow into the generated types.
Related
- Fields, the
fproxy, the chain-modifier model, and the shared modifiers (.required(),.default(),.array(),.localized(), …). f.select(), when a flag grows into a fixed set of more than two states.- Validation, the auto-derived Zod schema and the
.zod()escape hatch. - Relations, the full query language for combining the operators above.