generate:migration
Use the built-in CLI command for generating migrations to easily get up and running. Psychic will automatically timestamp the filename for your migrations, keeping them in sequential order, and will generate boilerplate to get you started with writing a migration.
pnpm psy g:migration --help
pnpm psy g:migration add-deleted-at-to-posts deleted_at:datetime:optional
Usage
pnpm psy g:migration [options] <migrationName> [columnsWithTypes...]
Arguments
-
<migrationName>: End with-to-table-nameor-from-table-nameto prepopulate with an alterTable command. -
[columnsWithTypes...]: Space separated snake-case (except for belongs_to model name) properties like this:title:citext subtitle:string body_markdown:text style:enum:post_styles:formal,informal User:belongs_toAll properties default to not nullable; null can be allowed by appending
:optional:subtitle:string:optionalSupported types
uuid,uuid[]: a column optimized for storing UUIDscitext,citext[]: case insensitive text (indexes and queries are automatically case insensitive)encrypted: encrypted text (used in conjunction with the@deco.Encrypteddecorator)string,string[]: varchar; allowed length defaults to 255, but may be customized, e.g.:subtitle:string:128orsubtitle:string:128:optionaltext,text[]boolean,boolean[]date,date[]datetime,datetime[]time,time[]timetz,timetz[]integer,integer[]decimal,decimal[]: precision,scale is required, e.g.:volume:decimal:3,2orvolume:decimal:3,2:optional- Leveraging arrays, add the "[]" suffix, e.g.:
volume:decimal[]:3,2
- Leveraging arrays, add the "[]" suffix, e.g.:
jsonb: prefer this overjsonunless you specifically need Postgres's non-normalizedjsonstorage. Reach for either only when the data genuinely can't be modeled as columns or an associated table — see Column Types — JSON for when ajsonbcolumn is (and isn't) the right call.enum,enum[]: include the enum name to automatically create the enum:type:enum:room_types:bathroom,kitchen,bedroomortype:enum:room_types:bathroom,kitchen,bedroom:optional- Omit the enum values to leverage an existing enum (omits the enum type creation):
type:enum:room_typesortype:enum:room_types:optional - Leveraging arrays, add the "[]" suffix, e.g.:
type:enum[]:room_types:bathroom,kitchen,bedroom
- Omit the enum values to leverage an existing enum (omits the enum type creation):
belongs_to: adds a foreign key to migration- Include the fully qualified model name, e.g., if the Coach model is in
src/app/models/Health/Coach:Health/Coach:belongs_to - Aliased FK shorthand — append
@aliasto generate a foreign key with a custom column name. This is the canonical pattern for_bycolumns (e.g.canceled_by_id) and for multiple foreign keys to the same model:InternalUser@canceled_by:belongs_to:optionalproduces thecanceled_by_idcolumn and its index from one token. A standaloneg:migrationwrites a migration and nothing else, so thecanceledByIdproperty and thecanceledByassociation are hand-added to the model afterward;g:modelandg:resourcewrite them for you. Examples:User@created_by:belongs_to—created_by_idFK,createdByassociationMessage@last_inbound:belongs_to:optional—last_inbound_idFK,lastInboundassociationMessage@last_outbound:belongs_to:optional—last_outbound_idFK,lastOutboundassociation
- Include the fully qualified model name, e.g., if the Coach model is in
Options
--connection-name <connectionName>: The connection name you wish to use for your migration.-h, --help: Display help for command.
Ending the migration name with -to-table-name will automatically include the underscored table name in the migration. When a name contains both markers, -to- wins regardless of where -from- appears; -from- only takes effect when the name has no -to- at all.
Because of this, a hand-written migration name (one with no columns passed, meant to be edited by hand) must avoid -to- and -from- entirely — either substring resolves the trailing text into a real table name and the generator fails when it can't find columns to pair with that table.
If you want to also generate a model for this migration, you can simply use the g:model or g:resource commands instead.
For schema changes that just add columns (or a foreign key) to an existing table, g:migration accepts the same column shorthand shown above — including Model:belongs_to and :optional. Hand-edit the generated migration only when the change isn't expressible as column shorthand, such as check constraints, enum alterations, or a custom backfill; see migrations for that reference.