Learn how to organize business logic using Phoenix contexts for clean separation of concerns.
What is a context in Phoenix?
A context is just an Elixir module that encapsulates domain/business logic and database operations, separating them from controllers and web code. It keeps controllers slim and the app organized.
Why use contexts?
- Prevents controllers from containing business logic or direct database interaction
- Encapsulates Ecto queries, product CRUD, etc., into clear, reusable functions
- Makes apps easier to maintain, refactor, and test
How to set up a context
- Convention: Context modules are plural (“Products”) and schemas are singular (“Product”)
- Move your schema (e.g., Product) into a sub-folder under your context (e.g.,
lib/shop/products/product.ex
)
- All DB and domain logic (listing, fetching by slug/id, creating, deleting products) go in the context, not the controller
Refactor workflow
- Controller calls functions like
Products.list_products()
or Products.find_product_by_slug(slug)
, rather than using Repo
directly
- Context exposes only what’s necessary for the controller/view layer
Adding CRUD to context
- List, find by slug, find by ID, create, and delete product functions are added to the context, each wrapping Ecto/Repo calls and any business logic
- You can add guards and pattern matching for safety
Testing/use in IEx
- With aliases/imports, you can quickly test context functions (
Products.list_products()
, Products.create_product(params)
) from the shell
Summary
Contexts formally separate “business logic” (CRUD, queries, domain rules) from the Phoenix web layer, keeping your codebase modular, maintainable, and idiomatic. Controllers become simple and focused by calling into contexts for all data concerns.