Skip to main content
An Orionjs application follows a modular, component-based architecture that promotes clean organization and separation of concerns.

Root Directory

App Directory

The app directory contains all the application code:

Component Structure

Each component follows a consistent structure:
Each component controller type folder has an index.ts (for example controllers/resolvers/index.ts) that exports an array of classes:

Component Definition

The component definition index.ts is always structured like this:

Controllers

Controllers are the entry points for code execution. Keep controllers thin - they should only:
  • Handle input validation
  • Call the appropriate services
  • Transform and return the response
Different types of controllers:
  • Route controllers: Handle HTTP endpoints
  • GraphQL resolvers: Handle GraphQL operations (preferred over routes for client APIs)
  • Job controllers: Handle scheduled or on-demand tasks
  • Echo controllers: Handle event-based communication

Resolvers Folder Organization

The resolvers folder should be organized by entity and action:
The index.ts exports all resolvers as a single array:

Configuration Structure

The config directory contains application-wide configuration:

Application Bootstrap

The application is bootstrapped in app/index.ts:

Component.md Management

Component.md serves as a memory store - it contains essential notes that help understand the component without reading all the code. Structure: Component.md should contain organized “notes” as bullet points, where each note is 2-5 phrases describing:
  • Key business logic and data flows
  • Important architectural decisions
  • External dependencies and integrations
  • Critical implementation details
  • Known issues or limitations
  • How to check for permissions
  • Anything else important about the component
Best Practices:
  • BEFORE any task: Read the Component.md file if it exists
  • IF no Component.md exists: Create it by reading the whole component folder
  • AFTER any schema, service, or controller changes: Update the Component.md with relevant notes
  • AFTER adding new features: Document important implementation details
What to include: Only store notes valuable for understanding the component’s purpose, behavior, and important implementation details. What NOT to include: Avoid temporary information, detailed code explanations, or information easily derived from code structure.

Scripts Directory

For one-off scripts or maintenance tasks, use the temp/scripts directory:
Scripts should:
  • Use tsx for execution: #!/usr/bin/env -S bunx tsx
  • Be named according to the task they perform
  • Be self-contained and documented
Example script:
Run with: bunx tsx temp/scripts/cleanup-orphaned-records.ts

Code Organization Guidelines

  • File size limit: Avoid files over 200-300 lines of code. Refactor at that point.
  • Loop preferences: Prefer for of or for await of over .forEach. Use .map for transformations.
  • Mock data: Mocking data is only needed for tests, never for dev or prod environments.
  • Avoid any: Always declare types for variables and function parameters/returns.
  • Code duplication: Check for existing similar code before writing new implementations.

Basic Principles

  • Use component-based architecture
  • Encapsulate functionality in components
    • One component per main domain
    • Each component should contain controllers, schemas, services, and repositories
  • Prefer usage of resolvers instead of routes
  • Use dependency injection for service dependencies with @Inject() decorator
  • Follow the single responsibility principle for services
  • Use repositories for database operations
  • Handle validation and error cases appropriately
    • Prefer throwing ValidationError when validation of data fails
    • Prefer throwing UserError when the error is not a system error