QUESTPIE
SchemaFields

Boolean field

The two-state flag. One `boolean` column, a `z.boolean()` schema, five filter operators, and no arguments to get wrong.

View markdown
SurfaceDetail
Signaturef.boolean()
Argumentsnone, there is no second form of the call
Columnboolean
Schemaz.boolean()
Filter operatorsthe boolean set, five entries, below
Admin forma checkbox, or a switch when you ask for one
Admin cella badge reading Yes or No
Type-specific methodsnone, the shared chain is the whole surface
src/questpie/server/collections/posts.ts
import { collection } from "#questpie/factories";

export const posts = collection("posts").fields(({ f }) => ({
	published: f.boolean().default(false).required(),
	featured: f.boolean(),
}));

published is NOT NULL with a Postgres default of false, and the key is optional on insert because the default fills it. featured is nullable, so it reads back as boolean | null and models three states rather than two.

Methods

The type declares no methods of its own. Three from the base chain carry the weight here.

MethodEffect
.required()NOT NULL, and the key is required on insert
.default(v)Writes a column default, and makes the key optional on insert
.localized()Moves the column into <collection>_i18n, one value per locale

.label(), .description(), .access(), .hooks() and the rest of the base chain behave here exactly as on any other type.

`.default()` is checked against `boolean`

The argument is constrained to the field's own data type, so f.boolean().default("yes") does not compile. It accepts a literal, a factory, or a raw SQL expression. The value lands on the Postgres column, not on the insert payload.

Filtering

Boolean carries booleanOps, five operators.

OperatorOperandMatches
eq / nebooleanEqual, not equal
notboolean, or nullNot equal, or IS NOT NULL when given null
isNull / isNotNullbooleanPass false and each inverts

A bare value is the shorthand for eq, and on a nullable boolean a bare null compiles to IS NULL. Both short forms live in the generated where type rather than beside it, and .required() drops null from it.

const { docs } = await app.collections.posts.find({
	where: { published: true, featured: { isNull: true } },
});

There is nothing else. No in, no gt, because a column with two values has nothing to order or enumerate.

In the admin

The form control is BooleanField, a checkbox. The list cell is BooleanCell, a badge reading Yes for a truthy value and No for everything else.

.admin() is the field extension @questpie/admin registers, and one key on it is boolean-specific.

KeyTypeDefaultEffect
displayAs"checkbox" | "switch""checkbox"Swaps the checkbox for a toggle switch
emailNotifications: f.boolean().default(true).admin({ displayAs: "switch" }),

The rest of the keys on .admin() are the shared ones every field takes.

`null` and `false` are indistinguishable

Both controls render !!value, so an unset boolean shows unchecked and its cell reads No. The change handler always writes true or false, which means the admin can never put null back once a person touches the control.

The list filter sheet cannot filter a boolean

It switches on the field registry name, boolean, while its two-state branch tests for checkbox and switch. Neither matches, so the field falls through to the presence-only list, is empty and is not empty. Filter through the API instead.

A localized boolean gets the locale indicator beside its label, the same as any other localized field.

Lists

.array() replaces the column with jsonb holding a list of booleans and swaps the five operators for the multi-value set.

answers: f.boolean().array().maxItems(20),

The admin has no control for a list of booleans

ArrayField picks its item control from an allowlist of five type names, and boolean is not among them, so each item falls back to a text input. What that input produces is a string, which z.array(z.boolean()) rejects on save.

Types

A boolean contributes boolean to the row, insert and update shapes, and nothing needs annotating.

type Post = typeof posts.$infer.select;
//   ^? { published: boolean; featured: boolean | null; ... }

.required() makes it non-null on read and required on insert. .default() makes it optional on insert. Without either, the key is optional and the value is boolean | null.

Select is where a flag belongs once it grows past two states, and it narrows the read type to the literal union of its values.

Arrays covers what .array() does to reads, writes and filters, and why the item control falls back to text.

Reading and writing has the rest of the query language, AND, OR, NOT, orderBy and pagination.

Validation covers the derived schema and .zod(), the way to add a check the type does not carry.

On this page