Skip to content

Best Practices ​

Production-ready patterns, security guidelines, and optimization strategies for building robust IGNIS applications. These best practices are distilled from real-world experience building enterprise applications.

Learning Path ​

1

Foundation

Architecture → Decisions Guide → Code Standards

Understand patterns and establish coding conventions
2

Data Layer

Data Modeling → API Patterns → Error Handling

Design your data layer and handle edge cases
3

Quality Assurance

Testing → Avoid Pitfalls → Troubleshooting

Write tests and prevent common mistakes
4

Production Ready

Security → Performance → Deployment

Secure, optimize, and deploy your application

Quick Reference ​

Essential Patterns ​

typescript
// ✅ Layered Architecture
Controller → Service → Repository → DataSource

// ✅ Dependency Injection
@inject({ key: BindingKeys.build({ namespace: BindingNamespaces.SERVICE, key: UserService.name }) })

// ✅ Error Handling
throw getError({ statusCode: 404, message: 'User not found' });

// ✅ Scoped Logging (ILogger - never names a provider)
this.logger.for('createUser').info('User created | id: %s', user.id);

// ✅ Input Validation
request: { body: jsonContent({ schema: z.object({ email: z.string().email() }) }) }

Anti-Patterns to Avoid ​

typescript
// ❌ Business logic in controllers
@get({ configs: RouteConfigs.GET_USER })
async getUser(context: TRouteContext) {
  const { id } = context.req.valid<{ id: string }>('param');
  const user = await this.userRepository.findById({ id });
  if (user.lastLogin < cutoff) await this.sendReminder(user); // Move to service!
  return context.json(user, HTTP.ResultCodes.RS_2.Ok);
}

// ❌ Catching all errors silently
try { await riskyOperation(); } catch (e) { /* swallowed */ }

// ❌ Raw Error - loses statusCode, messageCode and the normalized response shape
throw new Error('User not found'); // Use getError()

// ❌ Using `any` type
const data: any = await fetchData(); // Use proper types!

Security Checklist ​

CheckAction
SecretsStore in environment variables, never in code
InputValidate with Zod schemas at API boundaries
AuthProtect routes with authenticate: { strategies: [Authentication.STRATEGY_JWT] }
Sensitive dataUse hiddenProperties in model settings
File uploadsUse sanitizeFilename() for all user-provided filenames
CORSConfigure allowed origins explicitly

Performance Checklist ​

CheckAction
QueriesUse fields to select only needed columns
PaginationAlways set limit on find operations
RelationsLimit include depth to 2 levels max
Connection poolConfigure pool size based on load
Background jobsOffload CPU-intensive tasks to workers
CachingCache expensive queries with Redis

All Best Practices ​

Architecture & Design ​

GuideDescription
Architectural PatternsLayered architecture, DI, components, mixins
Architecture DecisionsWhen to use services, repositories, components

Development ​

GuideDescription
Code Style StandardsNaming conventions, types, oxlint, bun fmt
Data ModelingSchema design, enrichers, relations, migrations
API Usage ExamplesRouting, repositories, middleware, services

Quality ​

GuideDescription
Testing StrategiesUnit tests, integration tests, mocking, E2E
Error HandlingError patterns, structured errors, logging
Common PitfallsMistakes to avoid and how to fix them
Troubleshooting TipsDebug common issues quickly

Production ​

GuideDescription
Security GuidelinesAuthentication, validation, secrets, CORS
Performance OptimizationQuery optimization, caching, connection pooling
Deployment StrategiesDocker, Kubernetes, cloud platforms, CI/CD

Contributing ​

GuideDescription
Contribution WorkflowGit workflow, PR guidelines, code review

New to IGNIS?

Start with the Getting Started Guide for tutorials, then return here for production-ready patterns.

Production Deployment?

Before deploying, review the Security Guidelines and Deployment Strategies thoroughly.

See Also ​