Use Cases
Use cases model business scenarios through triggers and domain actions. They are the core of Craft's dynamic modeling approach.
Syntax
use_case "<name>" {
when <trigger>
<action>*
when <trigger>
<action>*
}Basic Example
use_case "Order Placement" {
when Customer places order
Order validates items
Order creates order record
Order notifies order.OrderCreated
}TIP
order.OrderCreated is a typed event ref — a dotted qualified id. The older quoted-string form (notifies "Order Created") still parses but is deprecated; see Deprecated: Quoted Event Strings below.
Triggers
Triggers define what starts a scenario. There are four types:
External Triggers
Initiated by actors:
when user submits registration
when admin approves order
when customer places order
when system sends notificationSyntax:
when <actor> <verb> [connector] <phrase>Connector words (optional): a, an, the, to, from, in, on, at, for, with, by
Event Triggers
Initiated by events:
when order.OrderPlaced
when auth.UserRegistered
when payment.PaymentProcessedSyntax:
when <event_ref>An <event_ref> is a dotted qualified id — the FQ Avro record name / OpenAPI operationId the event corresponds to in code. No quotes, no kind: prefix, no /.
TIP
Use past tense for event names: order.OrderPlaced not order.PlaceOrder
Domain Listener Triggers
Domains reacting to events:
when Payment listens order.OrderCreated
when Notification listens auth.UserRegistered
when Inventory listens order.OrderCancelledSyntax:
when <domain> listens <event_ref>CRON Triggers
Scheduled tasks:
when CRON runs daily cleanup
when CRON executes hourly syncSyntax:
when CRON [phrase]Actions
Actions describe what domains do. There are four types:
Synchronous Actions
Direct domain-to-domain communication:
Order asks Inventory to reserve items
Authentication asks Database to verify credentials
Payment asks Gateway for transaction statusSyntax:
<domain> asks <domain> [connector] <phrase>The target can also be a node slug for a cross-context/typed reference: Subscriptions asks bc:re/billing for a fresh charge attempt. See Node Slugs — a bare domain name like Inventory is still the normal short form.
The trailing <phrase> accepts special characters unquoted (! & * / # ? +), e.g. Subscriptions asks bc:re/billing for a fresh charge attempt (1! & 2!) — no need to quote punctuation.
Use when: One domain needs an immediate response from another.
Asynchronous Actions
Publish events:
Order notifies order.OrderCreated
Payment notifies payment.PaymentProcessed
Profile notifies profile.UserUpdatedSyntax:
<domain> notifies <event_ref>Use when: Other domains might want to react, but the publisher doesn't need a response.
TIP
notifies "Order Created" (quoted string) still parses but is deprecated — craft validate emits a craft/lint/deprecated-string-ref warning and points at the typed-ref form.
Internal Actions
Domain internal operations:
Order validates items
Profile creates user record
Authentication generates token
Inventory updates stock levelsSyntax:
<domain> <verb> [connector] <phrase>Use when: A domain does something internally without calling other domains.
Return Actions
Return responses:
Database returns to Authentication the user record
Payment returns confirmation
API returns to Client the error message
Gateway returns to Payment the transaction resultSyntax:
<domain> returns [to <domain>] [connector] <phrase>Use when: A domain returns data, especially in response to an asks action.
Deprecated: Quoted Event Strings
Older .craft files (and older docs) write event names as quoted strings:
Order notifies "Order Created"
when Payment listens "Order Created"This form still parses — craft validate won't reject it — but it's deprecated: every quoted event string emits a craft/lint/deprecated-string-ref warning pointing at the typed-ref replacement. Prefer the typed-ref form (notifies order.OrderCreated) in all new or extended files; only leave quoted strings where you're intentionally not migrating an existing file.
Complete Example
use_case "Order Processing" {
// External trigger: customer action
when Customer places order
Order validates product availability
Order asks Inventory to reserve items
Order calculates total amount
Order asks Payment to create payment request
Order notifies order.OrderCreated
// Domain listener: Payment reacts to Order Created
when Payment listens order.OrderCreated
Payment asks PaymentGateway to process transaction
PaymentGateway returns to Payment the transaction result
Payment updates payment status
Payment notifies payment.PaymentProcessed
// Domain listener: Notification reacts to Payment
when Notification listens payment.PaymentProcessed
Notification asks EmailService to send confirmation
Notification asks SMSService to send notification
// Domain listener: Inventory reacts to Payment
when Inventory listens payment.PaymentProcessed
Inventory confirms reservation
Inventory updates stock levels
}Event-Driven Pattern
use_case "User Registration" {
when user submits registration
Authentication validates email format
Authentication asks Database to check uniqueness
Profile creates initial profile
Authentication notifies auth.UserRegistered
when Profile listens auth.UserRegistered
Profile asks Database to store profile
Profile notifies profile.ProfileCreated
when Notification listens auth.UserRegistered
Notification asks EmailService to send welcome email
when Analytics listens auth.UserRegistered
Analytics records registration event
Analytics updates metrics
}Request-Response Pattern
use_case "Get User Profile" {
when Customer requests profile
API validates authentication token
API asks Profile for user data
Profile asks Database to fetch profile
Database returns to Profile the profile data
Profile returns to API the formatted profile
API returns to Customer the profile
}Error Handling Pattern
use_case "Process Payment" {
when Customer submits payment
Payment validates payment details
Payment asks Gateway to charge card
Gateway returns to Payment the transaction result
when Payment listens payment.TransactionFailed
Payment creates retry attempt
Payment notifies payment.PaymentFailed
when Order listens payment.PaymentFailed
Order cancels order
Order asks Inventory to release reservation
Order notifies order.OrderCancelled
}Best Practices
Use Past Tense for Events
✅ Good:
Order notifies order.OrderCreated
Payment notifies payment.PaymentProcessed❌ Bad:
Order notifies order.CreateOrder
Payment notifies payment.ProcessPaymentBe Specific with Actions
✅ Good:
Authentication validates email format
Order calculates total amount❌ Bad:
Authentication validates
Order calculatesUse Domain Names, Not Service Names
✅ Good:
Order asks Inventory to reserve items❌ Bad:
OrderService asks InventoryService to reserve itemsKeep Scenarios Focused
Each when block should represent a cohesive scenario.
✅ Good:
use_case "Order Processing" {
when Customer places order
// 5-10 related actions
when Payment listens order.OrderCreated
// 3-5 related actions
}❌ Bad:
use_case "Everything" {
when Customer places order
// 50+ unrelated actions
}Common Patterns
Saga Pattern
use_case "Distributed Transaction" {
when user initiates order
Order creates order
Order notifies order.OrderStarted
when Payment listens order.OrderStarted
Payment charges customer
Payment notifies payment.PaymentCompleted
when Inventory listens payment.PaymentCompleted
Inventory ships items
Inventory notifies inventory.ShipmentSent
when Order listens payment.PaymentFailed
Order cancels order
Order notifies order.OrderCancelled
}CQRS Pattern
use_case "Order Management" {
// Command side
when user creates order
OrderCommand validates order
OrderCommand stores order
OrderCommand notifies order.OrderCreated
// Query side
when OrderQuery listens order.OrderCreated
OrderQuery updates read model
OrderQuery indexes order data
}Next Steps
- See complete examples with multiple use cases
- Learn about services to organize domains
- Understand domains to structure your model