Migration guides
Coming from another framework or a hand-rolled Node stack? These guides cover the most common starting points and show what the equivalent piece looks like in Titan.
The advice across all of them: migrate one concern at a time. Don't try to flip the whole codebase to Titan in one PR. Start with one of:
- A new feature module — write it Titan-style; everything else stays where it is.
- One existing concern (auth, metrics, scheduling) — swap just that, leave business logic untouched.
- The bootstrap layer — move the app entry point into Titan's
Application.create; keep your existing services as@Injectableproviders.
Guides
| Source | What you keep, what you replace |
|---|---|
| From NestJS | Most concepts map 1:1; the deltas are decorator names, Netron for RPC, and lifecycle |
| From plain Express / Fastify | Add structure: module system, DI container, lifecycle, typed RPC |
| From prom-client | Replace the metrics layer alone — keep everything else |
Common patterns regardless of source
Strangler fig — module by module
The safest migration strategy is the strangler fig pattern:
At every checkpoint, the app boots, tests pass, prod stays up.
Boot-time bridging
If your legacy app has its own bootstrap, wrap it with Titan's
Application.create({ providers: [...] }):
import { Application } from '@omnitron-dev/titan';
import { existingService } from './legacy/services.js';
const app = await Application.create({
providers: [
[EXISTING_SERVICE_TOKEN, { useValue: existingService }],
],
modules: [
NewFeatureModule, // new code lives here
],
});
await app.start();
Legacy code keeps working; new Titan modules can @Inject into
it; you migrate at your own pace.
Two-way bridges
A Titan service can call a legacy function; a legacy function can call a Titan service via the container. Use this to migrate incrementally without duplicating logic.
// In a Titan service:
constructor(@Inject(LEGACY_PAYMENT_TOKEN) private readonly pay: any) {}
// Or from legacy code:
const titanService = container.resolve(NewService);
await titanService.doSomething();
Testing during migration
Run the new code under the same integration tests as the legacy code. If you can substitute implementations in DI, you can:
- Run tests against the legacy implementation — green.
- Switch the DI binding to the Titan implementation — re-run tests — green.
- Delete the legacy code.
This catches behavioural drift immediately.
See also
- Best Practices / Structuring services — where Titan-style services land
- Modules system / Defining modules — the new unit of composition
- Testing — how to verify the migration