Generate Ecto migrations from natural language or schema descriptions. Handles tables, columns, indexes, constraints, references, enums, and partitioning. Supports reversible migrations, data migrations, and multi-tenant patterns. Use when creating or modifying database schemas, adding indexes, altering tables, creating enums, or performing data migrations in an Elixir project.
数据来源:ClawHub。 在 ClawSkills 查看
选择你使用的 Agent
方法一:命令行安装(推荐)
推荐(无需提前安装 clawhub)
npx clawhub@latest --dir ~/.claude/skills install ecto-migrator或使用 clawhub CLI(需提前安装)
clawhub --dir ~/.claude/skills install ecto-migrator⚠️ 需要 Node.js 18+,没有 Node?请使用下方方法二直接下载 ZIP。 安装 Node.js →
方法二:手动下载安装(无需 Node)
下载 ZIP,解压后将文件夹放到以下路径,重启 Agent 即可:
安装路径
~/.claude/skills/ecto-migrator/💡解压后将文件夹放到上方路径,重启 Agent 即可生效
--- name: ecto-migrator description: "Generate Ecto migrations from natural language or schema descriptions. Handles tables, columns, indexes, constraints, references, enums, and partitioning. Supports reversible migrations, data migrations, and multi-tenant patterns. Use when creating or modifying database schemas, adding indexes, altering tables, creating enums, or performing data migrations in an Elixir project." ---
Parse the user's description and generate a migration file. Common patterns:
| User Says | Migration Action | |-----------|-----------------| | "Create users table with email and name" | create table(:users) with columns | | "Add phone to users" | alter table(:users), add :phone | | "Make email unique on users" | create unique_index(:users, [:email]) | | "Add tenant_id to all tables" | Multiple alter table with index | | "Rename status to state on orders" | rename table(:orders), :status, to: :state | | "Remove the legacy_id column from users" | alter table(:users), remove :legacy_id | | "Add a check constraint on orders amount > 0" | create constraint(:orders, ...) |
mix ecto.gen.migration <name>
# Generates: priv/repo/migrations/YYYYMMDDHHMMSS_<name>.exs
Name conventions: See references/column-types.md for complete type mapping and guidance. Key decisions: See references/index-patterns.md for detailed index guidance. Always index: | Rule: Never mix schema changes and data changes in the same migration. These are auto-reversible: Must define both directions: Phoenix 1.7+ supports Prefer Warning: Adding values to Postgres enums requires ... 安装 Ecto Migrator 后,可以对 AI 说这些话来触发它 Help me get started with Ecto Migrator Explains what Ecto Migrator does, walks through the setup, and runs a quick demo based on your current project Use Ecto Migrator to generate Ecto migrations from natural language or schema descriptions Invokes Ecto Migrator with the right parameters and returns the result directly in the conversation What can I do with Ecto Migrator in my data & analytics workflow? Lists the top use cases for Ecto Migrator, with example commands for each scenario 将技能文件夹放到 ~/.claude/skills/ecto-migrator/ 目录(个人级,所有项目可用),或 .claude/skills/ecto-migrator/(项目级)。重启 AI 客户端后,用 /ecto-migrator 主动调用,或让 AI 根据上下文自动发现并使用。 Ecto Migrator 支持 Claude、Cursor、OpenClaw,可与这些 AI 平台无缝集成,扩展其能力。 Ecto Migrator 可免费安装使用。请查阅仓库了解许可证信息。 Generate Ecto migrations from natural language or schema descriptions. Handles tables, columns, indexes, constraints, references, enums, and partitioning. Supports reversible migrations, data migrations, and multi-tenant patterns. Use when creating or modifying database schemas, adding indexes, altering tables, creating enums, or performing data migrations in an Elixir project. Automate my data & analytics tasks using Ecto Migrator Identifies repetitive steps in your workflow and sets up Ecto Migrator to handle them automatically Ecto Migrator 属于「Data & Analytics」分类,该分类的技能帮助 AI 智能体在此领域执行专业任务。create_,
add_,
create__
alter__add_
Migration Template
defmodule MyApp.Repo.Migrations.CreateUsers do
use Ecto.Migration
def change do
create table(:users, primary_key: false) do
add :id, :binary_id, primary_key: true
add :email, :string, null: false
add :name, :string, null: false
add :role, :string, null: false, default: "member"
add :metadata, :map, default: %{}
add :tenant_id, :binary_id, null: false
add :team_id, references(:teams, type: :binary_id, on_delete: :delete_all)
timestamps(type: :utc_datetime_usec)
end
create unique_index(:users, [:tenant_id, :email])
create index(:users, [:tenant_id])
create index(:users, [:team_id])
end
endColumn Types
:binary_id (UUID) — set primary_key: false on table, add :id manually.:integer (cents) or :decimal — never :float.timestamps(type: :utc_datetime_usec).:string with app-level Ecto.Enum — avoid Postgres enums (hard to migrate).:map (maps to jsonb).{:array, :string} etc.Index Strategies
When to Add Indexes
_id columns)tenant_id (first column in composite indexes)WHERE clausesORDER BYIndex Types
# Standard B-tree
create index(:users, [:tenant_id])
# Unique
create unique_index(:users, [:tenant_id, :email])
# Partial (conditional)
create index(:orders, [:status], where: "status != 'completed'", name: :orders_active_status_idx)
# GIN for JSONB
create index(:events, [:metadata], using: :gin)
# GIN for array columns
create index(:posts, [:tags], using: :gin)
# Composite
create index(:orders, [:tenant_id, :status, :inserted_at])
# Concurrent (no table lock — use in separate migration)
@disable_ddl_transaction true
@disable_migration_lock true
def change do
create index(:users, [:email], concurrently: true)
endConstraints
# Check constraint
create constraint(:orders, :amount_must_be_positive, check: "amount > 0")
# Exclusion constraint (requires btree_gist extension)
execute "CREATE EXTENSION IF NOT EXISTS btree_gist", ""
create constraint(:reservations, :no_overlapping_bookings,
exclude: ~s|gist (room_id WITH =, tstzrange(starts_at, ends_at) WITH &&)|
)
# Unique constraint (same as unique_index for most purposes)
create unique_index(:accounts, [:slug])References (Foreign Keys)
add :user_id, references(:users, type: :binary_id, on_delete: :delete_all), null: false
add :team_id, references(:teams, type: :binary_id, on_delete: :nilify_all)
add :parent_id, references(:categories, type: :binary_id, on_delete: :nothing)on_delete | Use When | |-------------|----------| | :delete_all | Child can't exist without parent (memberships, line items) | | :nilify_all | Child should survive parent deletion (optional association) | | :nothing | Handle in application code (default) | | :restrict | Prevent parent deletion if children exist |Multi-Tenant Patterns
Every Table Gets tenant_id
def change do
create table(:items, primary_key: false) do
add :id, :binary_id, primary_key: true
add :name, :string, null: false
add :tenant_id, :binary_id, null: false
timestamps(type: :utc_datetime_usec)
end
# Always composite index with tenant_id first
create index(:items, [:tenant_id])
create unique_index(:items, [:tenant_id, :name])
endAdding tenant_id to Existing Tables
def change do
alter table(:items) do
add :tenant_id, :binary_id
end
# Backfill in a separate data migration, then:
# alter table(:items) do
# modify :tenant_id, :binary_id, null: false
# end
endData Migrations
Safe Data Migration Pattern
defmodule MyApp.Repo.Migrations.BackfillUserRoles do
use Ecto.Migration
# Don't use schema modules — they may change after this migration runs
def up do
execute """
UPDATE users SET role = 'member' WHERE role IS NULL
"""
end
def down do
# Data migrations may not be reversible
:ok
end
endBatched Data Migration (large tables)
def up do
execute """
UPDATE users SET role = 'member'
WHERE id IN (
SELECT id FROM users WHERE role IS NULL LIMIT 10000
)
"""
# For very large tables, use a Task or Oban job instead
endReversible vs Irreversible
Reversible (use
change)create table ↔ drop tableadd column ↔ remove columncreate index ↔ drop indexrename ↔ renameIrreversible (use
up/down)modify column type — Ecto can't infer the old typeexecute raw SQLdef up do
alter table(:users) do
modify :email, :citext, from: :string # from: helps reversibility
end
end
def down do
alter table(:users) do
modify :email, :string, from: :citext
end
endUsing
modify with from:from: for reversible modify:def change do
alter table(:users) do
modify :email, :citext, null: false, from: {:string, null: true}
end
endPostgreSQL Extensions
def change do
execute "CREATE EXTENSION IF NOT EXISTS citext", "DROP EXTENSION IF EXISTS citext"
execute "CREATE EXTENSION IF NOT EXISTS pgcrypto", "DROP EXTENSION IF EXISTS pgcrypto"
execute "CREATE EXTENSION IF NOT EXISTS pg_trgm", "DROP EXTENSION IF EXISTS pg_trgm"
endEnum Types (PostgreSQL native — use sparingly)
Ecto.Enum with :string columns. If you must use Postgres enums:def up do
execute "CREATE TYPE order_status AS ENUM ('pending', 'confirmed', 'shipped', 'delivered')"
alter table(:orders) do
add :status, :order_status, null: false, default: "pending"
end
end
def down do
alter table(:orders) do
remove :status
end
execute "DROP TYPE order_status"
endALTER TYPE ... ADD VALUE which cannot run inside a transaction. Prefer :string + Ecto.Enum.Checklist
Prompt 示例
UAUAUA常见问题
如何安装 Ecto Migrator?▾
Ecto Migrator 支持哪些 AI 平台?▾
Ecto Migrator 是免费的吗?▾
Ecto Migrator 有什么功能?▾
Ecto Migrator 属于哪个分类?▾
使用场景
同类技能推荐
查看全部 Data & Analytics →UA359