Column Constraint Annotations
These annotations control the database column type, constraints, and indexes. They're processed by the schema generator and migrator to produce DDL.
@auto — Auto-increment
// @auto (SQLite: INTEGER PRIMARY KEY AUTOINCREMENT, Postgres: SERIAL, MySQL: AUTO_INCREMENT)
// @auto;@primaryKey
id: number;Marks the column as auto-incrementing. Typically combined with @primaryKey. The database generates the value on insert; SlintORM never writes to this field.
@primaryKey — Primary Key
// @auto;@primaryKey
id: number;
// Composite primary key (multiple fields with @primaryKey)
// In a junction table:
userId: number; // @primaryKey
teamId: number; // @primaryKeyMarks the field as the primary key. Used by .get(), entity.refresh(), entity.update(), and entity.delete() to identify rows. Supports composite keys.
@unique — Unique Constraint
// @unique
email: string;
// Unique constraint with explicit name (Postgres/MySQL):
// @unique:uq_users_email
email: string;Creates a UNIQUE constraint on the column. Duplicate values throw ORMError.UNIQUE_VIOLATION.
@index — Database Index
// @index
teamId: number;
// Composite index across multiple fields:
// On the foreign key field:
teamId: number; // @index;@relation manytoone:Team;foreignKey:teamIdCreates a database index on the column. Speeds up queries that filter or sort by this field.
@nullable / @not null — Nullability
// @nullable — allows NULL values
bio?: string; // @nullable (optional fields are nullable by default)
// @not null — explicitly NOT NULL
role: string; // @not null (required fields are NOT NULL by default)Controls NULL / NOT NULL in DDL. Generally, TypeScript ? optional fields map to @nullable, and required fields map to NOT NULL.
@length:N — Column Length
// @length:500 — VARCHAR(500) in SQL, TEXT in SQLite
summary: string;Sets VARCHAR(N) for MySQL/Postgres. SQLite ignores length but the migrator still records it.
@default:value — Default Value
// @default:user
role: string;
// @default:'active' (quoted strings preserve quotes)
status: string;
// @default:0
count: number;
// @default:CURRENT_TIMESTAMP
createdAt: string;Sets the DEFAULT value in DDL. For string defaults, use single quotes: @default:\'active\'. Raw values (unquoted) are treated as SQL expressions (e.g. CURRENT_TIMESTAMP).
@enum:(a,b,c) — Enum Constraint
// @enum:(pending,active,banned)
status: string;
// Valid: "pending", "active", "banned"
// Invalid: "deleted", "archived"Creates a CHECK constraint (SQLite/Postgres) or ENUM type (MySQL). Values outside the enum set throw ORMError.CHECK_VIOLATION.
@comment:text — Column Comment
// @comment:User's display name (visible in database tools)
name: string;Adds a COMMENT to the column (MySQL/Postgres). Useful for database documentation.
@softDelete — Soft Delete
// @softDelete
deletedAt: string;
// Queries auto-filter: WHERE deletedAt IS NULL
await User.getAll(); // excludes deleted rows
// Include or filter deleted:
await User.query().withTrashed().get(); // all rows
await User.query().onlyTrashed().get(); // only deleted
// Restore:
await User.restore({ id: 1 }); // sets deletedAt = NULLSee the full Soft Delete docs for details.
Errors
| Error | Cause | Fix |
|---|---|---|
ORMError: UNIQUE_VIOLATION | Duplicate value in @unique column | Use upsert() or check before insert |
ORMError: CHECK_VIOLATION | Value not in @enum list | Use one of the listed enum values |
ORMError: NOT_NULL_VIOLATION | null in a NOT NULL column | Provide a value or mark as @nullable |
| No primary key defined | No field has @primaryKey | Add @primaryKey to at least one field |
Conventions
- Always have exactly one
@primaryKeyfield (or a composite primary key) - Optional fields (
?in TypeScript) are implicitly@nullable @autois only needed for integer primary keys — string UUIDs use@randominstead- Use
@uniquefor business keys (email, slug); use@indexfor foreign keys