Appearance
Use Cases
Application-specific business rules that orchestrate the flow of data through your system
Related Concepts: Application Service | Domain Service | Clean Architecture
What Are Use Cases?
A use case represents a specific business functionality—a discrete action that your system can perform. It describes "how an automated system is used" including the input it receives, the output it produces, and the processing steps it performs. Use cases are the application-specific business rules that give your software its unique value.
In Clean Architecture, use cases live in the second layer, orchestrating the interaction between pure domain logic (Entities) and the technical details of the outside world (Interface Adapters). They are the conductors of your application's symphony, coordinating various parts to achieve specific business goals.
Why Use Cases Matter
Clear Intent
Each use case has a single, well-defined purpose that maps directly to a business requirement. When you read CreateOrderUseCase or ProcessRefundUseCase, you immediately understand what business capability it provides. This clarity makes codebases self-documenting and business-aligned.
Isolation of Business Logic
Use cases encapsulate application-specific business rules separately from both domain entities and technical infrastructure. This isolation means your business workflows aren't tangled with HTTP concerns, database queries, or framework details.
Testability
Because use cases depend only on abstractions (interfaces), they can be tested in complete isolation. You can verify complex business workflows without setting up databases, web servers, or external services—just pure business logic testing.
Reusability
A single use case can be triggered from multiple delivery mechanisms: REST APIs, GraphQL, CLI commands, message queues, or scheduled jobs. The business logic remains the same regardless of how it's invoked.
Anatomy of a Use Case
A well-designed use case typically contains:
Input Data (Request Model)
Plain data structures that carry the information needed to execute the use case. These should be framework-agnostic—no HTTP request objects or database models.
Business Logic Orchestration
The core responsibility: coordinating domain entities, enforcing business rules, and managing the workflow.
Dependencies (Ports)
Interfaces that define what the use case needs from the outside world: repositories for data access, services for notifications, gateways for external systems.
Output Data (Response Model)
Plain data structures that carry the results of the use case execution. Again, framework-agnostic.
Error Handling
Business-relevant exceptions and error cases that might occur during execution.
Use Case Responsibilities
What Use Cases DO
Orchestrate Domain Logic
- Call methods on entities
- Coordinate multiple entities to achieve a goal
- Apply application-specific business rules
Manage Transactions
- Define transaction boundaries
- Ensure consistency across operations
- Handle rollback scenarios
Enforce Business Invariants
- Validate that operations are allowed
- Check business preconditions
- Ensure postconditions are met
Coordinate External Services
- Send notifications (through interfaces)
- Call external APIs (through gateways)
- Trigger events (through publishers)
What Use Cases DON'T DO
Know About Delivery Mechanisms
- No HTTP status codes
- No request/response objects
- No framework-specific annotations
Contain Technical Implementation
- No SQL queries
- No API calls
- No file I/O
Format Output
- No JSON serialization
- No HTML generation
- No UI concerns
Use Cases as Workflows
Use cases can be thought of as workflows—functional pipelines that transform inputs into outputs while coordinating various system components. They should read like a clear description of a business process:
1. Validate input data
2. Load required entities from repository
3. Apply business rules using domain logic
4. Persist changes through repository
5. Send notifications via notification service
6. Return success responseThis workflow abstraction makes use cases predictable, testable, and easy to understand.
Patterns and Best Practices
Single Responsibility
Each use case should do one thing well. "CreateOrderAndSendEmailAndUpdateInventory" is doing too much—split it into composed use cases.
Command-Query Separation
Consider separating use cases that modify state (commands) from those that retrieve data (queries). This makes intent clearer and enables different optimization strategies.
Explicit Dependencies
Use constructor injection to make dependencies explicit. A use case's constructor signature should tell you everything it needs to function.
Return Rich Results
Don't just return void or boolean. Return result objects that carry both success/failure status and relevant data, making error handling explicit and type-safe.
Keep Use Cases Thin
Use cases orchestrate—they shouldn't contain complex business logic. Push complexity into domain entities or domain services.
Common Misconceptions
"Use Cases Are Just Services"
While they might be implemented as service classes, use cases are more specific: they represent single business operations with clear inputs and outputs, not grab-bags of related functionality.
Note: In Domain-Driven Design, the equivalent pattern is called an Application Service. At Synapse, we prefer "Use Case" terminology as it's more widely understood and business-focused.
"Every Method Needs a Use Case"
Simple CRUD operations might not warrant full use cases if there's no business logic. However, as soon as business rules enter the picture, use cases provide valuable structure.
"Use Cases Make Systems Complex"
Use cases don't add complexity—they reveal and organize the complexity that already exists in your business requirements. They make implicit workflows explicit.
Coordinating Domain Behaviors
Use cases excel at coordinating multiple domain behaviors to achieve business goals. They act as the bridge between pure domain logic and practical application needs:
- Save domain entities - Persist changes after business operations
- Notify users about events - Trigger notifications when important things happen
- Integrate with external systems - Coordinate with payment providers, email services, etc.
- Enforce workflow rules - Ensure operations happen in the correct order
The key is that use cases know what needs to be done, but not how it's technically accomplished. They declare their needs through interfaces, keeping them pure and testable.
Applied In
The following implementation guides demonstrate use cases in practice:
- Clean Architecture in NestJS Modules - Implementing use cases with dependency injection and TypeScript
- Unit Testing in NestJS - Testing use cases in isolation
- React Design Guidelines (coming soon) - Frontend application services as use cases
- Acceptance Testing Guidelines - Testing use cases through user scenarios
Related Concepts
- Clean Architecture - The architectural context where use cases fit
- Dependency Inversion & Ports/Adapters - How use cases achieve independence from technical details
- Application Service - The DDD equivalent of Use Cases
- Domain Service - For domain logic that doesn't belong in entities
Further Reading
- Use Case Workflow Pattern - Synapse's workflow-oriented approach to use cases
- Clean Architecture by Robert C. Martin - Chapter 20: Business Rules
- Implementing Domain-Driven Design by Vaughn Vernon - Application Services