Skip to content
cccskills
FreePublished on GitHub

ecto

Design and debug Elixir persistence with Ecto. Use for schemas, changesets, queries, preloads, transactions, migrations, multi-tenancy, and data access through application contexts. Covers database query performance and connection pools.

The English summary is being prepared. Showing the original description.

Works withPostgreSQL
See how to install

Files included (1)

  • SKILL.md4.6 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Ecto

Model persistence, compose queries, and keep data access within application boundaries.

Context = Setting That Changes Meaning

Context isn't just a namespace—it changes what words mean. "Product" means different things in Checkout (SKU, name), Billing (SKU, cost), and Fulfillment (SKU, warehouse). Each bounded context may have its OWN Product schema/table.

Think top-down: Subdomain → Context → Entity. Not "What context does Product belong to?" but "What is a Product in this business domain?"

Cross-Context References: IDs, Not Associations

schema "cart_items" do
  field :product_id, :integer  # Reference by ID
  # NOT: belongs_to :product, Catalog.Product
end

Query through the context, not across associations. Keeps contexts independent and testable.

DDD Patterns as Pipelines

def create_product(params) do
  params
  |> Products.build()       # Factory: unstructured → domain
  |> Products.validate()    # Aggregate: enforce invariants
  |> Products.insert()      # Repository: persist
end

Use events (as data structs) to compose bounded contexts with minimal coupling.

Schema ≠ Database Table

Use CaseApproach
Database tableStandard schema/2
Form validation onlyembedded_schema/1
API request/responseEmbedded schema or schemaless

Multiple Changesets per Schema

def registration_changeset(user, attrs)  # Full validation + password
def profile_changeset(user, attrs)       # Name, bio only
def admin_changeset(user, attrs)         # Role, verified_at

Different operations = different changesets.

Multi-Tenancy: Composite Foreign Keys

add :post_id, references(:posts, with: [org_id: :org_id], match: :full)

Use prepare_query/3 for automatic scoping. Raise if org_id missing.

Preload vs Join Trade-offs

ApproachBest For
Separate preloadsHas-many with many records (less memory)
Join preloadsBelongs-to, has-one (single query)

Join preloads can use 10x more memory for has-many.

CRUD Contexts Are Fine

"If you have a CRUD bounded context, go for it. No need to add complexity."

Use generators for simple cases. Add DDD patterns only when business logic demands it.

Gotchas from Core Team

CTE Queries Don't Inherit Schema Prefix

In multi-tenant apps, CTEs don't get the parent query's prefix.

Fix: Explicitly set prefix: %{recursive_query | prefix: "tenant"}

Parameterized Queries ≠ Prepared Statements

  • Parameterized queries: WHERE id = $1 — always used by Ecto
  • Prepared statements: Query plan cached by name — can be disabled

pgbouncer: Use prepare: :unnamed (disables prepared statements, keeps parameterized queries).

pool_count vs pool_size

More pools with fewer connections = better for benchmarks. But with mixed fast/slow queries, a single larger pool gives better latency.

Rule: pool_count for uniform workloads, larger pool_size for real apps.

Sandbox Mode Doesn't Work With External Processes

Cachex, separate GenServers, or anything outside the test process won't share the sandbox transaction.

Fix: Make the external service use the test process, or accept it's not in the same transaction.

Null Bytes Crash Postgres

PostgreSQL rejects null bytes even though they're valid UTF-8.

Fix: Sanitize at boundaries: String.replace(string, "\x00", "")

preload_order for Association Sorting

has_many :comments, Comment, preload_order: [desc: :inserted_at]

Note: Doesn't work for through associations.

Runtime Migrations Use List API

Ecto.Migrator.run(Repo, [{0, Migration1}, {1, Migration2}], :up, opts)

Idioms

  • Prefer Repo.insert/1 over Repo.insert!/1—handle {:ok, _} / {:error, _} explicitly
  • Use Repo.transact/1 (Ecto 3.12+) for simple transactions instead of Ecto.Multi

Red Flags - STOP and Reconsider

  • belongs_to pointing to another context's schema
  • Single changeset for all operations
  • Preloading has-many with join
  • CTEs in multi-tenant apps without explicit prefix
  • Using pgbouncer without prepare: :unnamed
  • Testing with Cachex/GenServers assuming sandbox shares transactions
  • Accepting user input without null byte sanitization

Any of these? Re-read the Gotchas section.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

elixir

Free

Write and refactor idiomatic Elixir functions, modules, and data structures. Use for pattern matching, control flow, error handling, protocols, behaviours, and deciding whether a process is needed. Use otp for process design and supervision.

The English summary is being prepared. Showing the original description.

georgeguimaraes/elixir-agent-tools189Updated Sep 20, 2026

oban

Free

Build and debug durable background jobs with Oban and Oban Pro. Use for workers, job argument serialization, retries, scheduled or recurring jobs, uniqueness, batches, and workflows. Use otp for in-memory tasks and process supervision.

The English summary is being prepared. Showing the original description.

georgeguimaraes/elixir-agent-tools189Updated Sep 20, 2026

otp

Free

Design and debug Elixir runtime concurrency, process state, and supervision. Use for GenServer, Supervisor, Task, Registry, ETS, process bottlenecks, and Broadway pipelines. Use oban for durable background jobs, retries, and scheduling.

The English summary is being prepared. Showing the original description.

georgeguimaraes/elixir-agent-tools189Updated Sep 20, 2026

Build and debug Phoenix web interfaces and HTTP endpoints. Use for LiveView lifecycle and data loading, components, forms, routes, controllers, Plug, channels, and PubSub. Use ecto for changesets, queries, and persistence behind those interfaces.

The English summary is being prepared. Showing the original description.

georgeguimaraes/elixir-agent-tools189Updated Sep 20, 2026

See all skills by georgeguimaraes

Report a problem with this skill