npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@riktajs/typeorm

v0.11.5

Published

TypeORM integration for Rikta Framework with lifecycle-based connection management

Readme

@riktajs/typeorm

TypeORM integration for Rikta Framework with lifecycle-based connection management

npm version License: MIT

Features

  • 🔌 Automatic Connection Management - DataSource initializes on app start, closes on shutdown
  • 💉 Dependency Injection - Inject DataSource and EntityManager via @Autowired
  • ⚙️ Programmatic Configuration - Configure via createTypeOrmProvider() function
  • 🔄 Lifecycle Hooks - Uses Rikta's OnProviderInit and OnProviderDestroy
  • 📦 Re-exported Decorators - Import TypeORM decorators directly from this package
  • 🎯 Type-safe - Full TypeScript support

Installation

npm install @riktajs/typeorm typeorm

You'll also need a database driver:

# PostgreSQL
npm install pg

# MySQL / MariaDB
npm install mysql2

# SQLite
npm install better-sqlite3

# Microsoft SQL Server
npm install mssql

Peer Dependencies

  • @riktajs/core >= 0.4.2
  • typeorm >= 0.3.0
  • reflect-metadata >= 0.2.0

Quick Start

1. Create an Entity

import { Entity, Column, PrimaryGeneratedColumn } from '@riktajs/typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column()
  name!: string;

  @Column({ unique: true })
  email!: string;

  @Column({ default: true })
  isActive!: boolean;
}

2. Create a Service

import { Injectable, Autowired } from '@riktajs/core';
import { TYPEORM_DATA_SOURCE } from '@riktajs/typeorm';
import type { DataSource } from '@riktajs/typeorm';
import { User } from './entities/user.entity';

@Injectable()
export class UserService {
  @Autowired(TYPEORM_DATA_SOURCE)
  private dataSource!: DataSource;

  async findAll(): Promise<User[]> {
    return this.dataSource.getRepository(User).find();
  }

  async findById(id: number): Promise<User | null> {
    return this.dataSource.getRepository(User).findOneBy({ id });
  }

  async create(name: string, email: string): Promise<User> {
    const user = new User();
    user.name = name;
    user.email = email;
    return this.dataSource.getRepository(User).save(user);
  }
}

3. Use in a Controller

import { Controller, Get, Post, Body, Autowired } from '@riktajs/core';
import { UserService } from './user.service';

@Controller('/users')
export class UserController {
  @Autowired()
  private userService!: UserService;

  @Get('/')
  async listUsers() {
    return this.userService.findAll();
  }

  @Post('/')
  async createUser(@Body() body: { name: string; email: string }) {
    return this.userService.create(body.name, body.email);
  }
}

4. Bootstrap the Application

import 'reflect-metadata';
import { Rikta } from '@riktajs/core';
import { initializeTypeOrm } from '@riktajs/typeorm';
import { User } from './entities/user.entity';

async function bootstrap() {
  // Initialize TypeORM (automatically connects and registers in DI container)
  const { installCleanup } = await initializeTypeOrm({
    type: 'postgres',
    host: 'localhost',
    port: 5432,
    username: 'admin',
    password: 'secret',
    database: 'myapp',
    entities: [User], // Register your entities
    synchronize: false, // Set to true only in development
    logging: true,
  });

  const app = await Rikta.create({
    port: 3000,
  });

  // Install automatic cleanup on app shutdown
  installCleanup(app);

  await app.listen();
}

bootstrap();

The installCleanup(app) call ensures that TypeORM connections are automatically closed when app.close() is called or when the process terminates gracefully.

If you need more control, you can initialize manually:

import 'reflect-metadata';
import { Rikta, Container } from '@riktajs/core';
import { createTypeOrmProvider, TYPEORM_DATA_SOURCE, TYPEORM_ENTITY_MANAGER } from '@riktajs/typeorm';
import { User } from './entities/user.entity';

async function bootstrap() {
  // Create and configure the TypeORM provider
  const typeormProvider = createTypeOrmProvider({
    dataSourceOptions: {
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'admin',
      password: 'secret',
      database: 'myapp',
      entities: [User], // Register your entities
      synchronize: false, // Set to true only in development
      logging: true,
    },
  });

  // Initialize the provider (connects to database)
  await typeormProvider.onProviderInit();

  // Register DataSource in the container so services can inject it
  const container = Container.getInstance();
  container.registerValue(TYPEORM_DATA_SOURCE, typeormProvider.getDataSource());
  container.registerValue(TYPEORM_ENTITY_MANAGER, typeormProvider.getEntityManager());

  const app = await Rikta.create({
    port: 3000,
  });

  await app.listen();
  
  // Cleanup on shutdown
  process.on('SIGTERM', async () => {
    await typeormProvider.onProviderDestroy();
    await app.close();
  });
}

bootstrap();

Configuration

All configuration must be provided programmatically through initializeTypeOrm() or createTypeOrmProvider(). This ensures type safety and makes it explicit which entities and options are being used.

Basic Configuration

import { initializeTypeOrm } from '@riktajs/typeorm';
import { User } from './entities/user.entity';

const { installCleanup } = await initializeTypeOrm({
  type: 'postgres',
  host: 'localhost',
  port: 5432,
  username: 'admin',
  password: 'secret',
  database: 'myapp',
  entities: [User], // Always required
  synchronize: false, // Set to true only in development!
  logging: true,
});

// Don't forget to call installCleanup(app) after creating your Rikta app

Using Environment Variables

You can still use environment variables by reading them in your bootstrap code:

const { installCleanup } = await initializeTypeOrm({
    type: process.env.DB_TYPE as any,
    host: process.env.DB_HOST,
    port: parseInt(process.env.DB_PORT || '5432'),
    username: process.env.DB_USERNAME,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_DATABASE,
    entities: [User, Post, Comment],
    synchronize: process.env.NODE_ENV === 'development',
    logging: process.env.NODE_ENV === 'development',
  },
});

Multiple Entities

Use an array to register multiple entities:

import { User } from './entities/user.entity';
import { Post } from './entities/post.entity';
import { Comment } from './entities/comment.entity';

await initializeTypeOrm({
  // ... other options
  entities: [User, Post, Comment],
});

Entity Auto-Discovery with Glob Patterns

For larger projects, use glob patterns to auto-discover entities:

const typeormProvider = createTypeOrmProvider({
  dataSourceOptions: {
    // ... other options
    entities: ['src/entities/**/*.entity.{ts,js}'],
    // In production build:
    // entities: ['dist/entities/**/*.entity.js'],
  },
});

Injection Tokens

| Token | Type | Description | |-------|------|-------------| | TYPEORM_DATA_SOURCE | DataSource | The TypeORM DataSource instance | | TYPEORM_ENTITY_MANAGER | EntityManager | The EntityManager for the default connection |

Using EntityManager

import { Injectable, Autowired } from '@riktajs/core';
import { TYPEORM_ENTITY_MANAGER } from '@riktajs/typeorm';
import type { EntityManager } from '@riktajs/typeorm';

@Injectable()
export class TransactionService {
  @Autowired(TYPEORM_ENTITY_MANAGER)
  private entityManager!: EntityManager;

  async transferFunds(fromId: number, toId: number, amount: number) {
    await this.entityManager.transaction(async (manager) => {
      // All operations here run in a transaction
      await manager.decrement(Account, { id: fromId }, 'balance', amount);
      await manager.increment(Account, { id: toId }, 'balance', amount);
    });
  }
}

Lifecycle

The TypeOrmProvider integrates with Rikta's lifecycle system:

Rikta.create()
│
├─ Initialize providers (sorted by priority)
│   └─ TypeOrmProvider (priority: 100)
│       ├─ Build DataSourceOptions
│       ├─ Create DataSource
│       ├─ Call dataSource.initialize()
│       └─ Register in DI container
│
├─ ... other providers ...
│
app.close()
│
└─ Destroy providers (reverse order)
    └─ TypeOrmProvider
        └─ Call dataSource.destroy()

Priority

TypeOrmProvider has a priority of 100, ensuring the database connection is established before other services that depend on it.

Re-exported Decorators

For convenience, this package re-exports commonly used TypeORM decorators:

import {
  // Entity
  Entity,
  ViewEntity,
  
  // Columns
  Column,
  PrimaryColumn,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
  DeleteDateColumn,
  VersionColumn,
  
  // Relations
  OneToOne,
  OneToMany,
  ManyToOne,
  ManyToMany,
  JoinColumn,
  JoinTable,
  
  // Indexes
  Index,
  Unique,
  
  // Subscribers
  EventSubscriber,
  BeforeInsert,
  AfterInsert,
  BeforeUpdate,
  AfterUpdate,
} from '@riktajs/typeorm';

Advanced Usage

Custom Repository Pattern

import { Injectable } from '@riktajs/core';
import { TYPEORM_DATA_SOURCE } from '@riktajs/typeorm';
import type { DataSource, Repository } from '@riktajs/typeorm';
import { User } from './entities/user.entity';

@Injectable()
export class UserRepository {
  private repository!: Repository<User>;

  @Autowired(TYPEORM_DATA_SOURCE)
  set dataSource(ds: DataSource) {
    this.repository = ds.getRepository(User);
  }

  async findActive(): Promise<User[]> {
    return this.repository.find({
      where: { isActive: true },
    });
  }

  async findByEmail(email: string): Promise<User | null> {
    return this.repository.findOneBy({ email });
  }
}

Query Builder

@Injectable()
export class ReportService {
  @Autowired(TYPEORM_DATA_SOURCE)
  private dataSource!: DataSource;

  async getUserStats() {
    return this.dataSource
      .getRepository(User)
      .createQueryBuilder('user')
      .select('user.isActive', 'status')
      .addSelect('COUNT(*)', 'count')
      .groupBy('user.isActive')
      .getRawMany();
  }
}

Retry Configuration

For unstable connections, configure retry behavior:

const typeormProvider = createTypeOrmProvider({
  dataSourceOptions: {
    type: 'postgres',
    host: 'db.example.com',
    port: 5432,
    username: 'admin',
    password: 'secret',
    database: 'myapp',
    entities: [User],
  },
  retryAttempts: 3,
  retryDelay: 5000, // 5 seconds
});

Multiple DataSources

Connect to multiple databases using named providers:

import { 
  createNamedTypeOrmProvider, 
  getDataSourceToken,
} from '@riktajs/typeorm';
import { User, Post } from './entities/main';
import { Event, Metric } from './entities/analytics';

// Create providers for each database
const mainDb = createNamedTypeOrmProvider('main', {
  type: 'postgres',
  host: 'main-db.example.com',
  database: 'main',
  entities: [User, Post],
});

const analyticsDb = createNamedTypeOrmProvider('analytics', {
  type: 'postgres',
  host: 'analytics-db.example.com',
  database: 'analytics',
  entities: [Event, Metric],
});

// Use both providers in Rikta
const app = await Rikta.create({
  port: 3000,
  providers: [mainDb, analyticsDb],
});

Inject named datasources in your services:

import { Injectable, Autowired } from '@riktajs/core';
import { getDataSourceToken } from '@riktajs/typeorm';
import type { DataSource } from '@riktajs/typeorm';

// Get tokens for named connections
const MAIN_DS = getDataSourceToken('main');
const ANALYTICS_DS = getDataSourceToken('analytics');

@Injectable()
class AnalyticsService {
  @Autowired(ANALYTICS_DS)
  private analyticsDs!: DataSource;

  @Autowired(MAIN_DS)
  private mainDs!: DataSource;

  async trackEvent(userId: number, event: string) {
    // Get user from main database
    const user = await this.mainDs.getRepository(User).findOneBy({ id: userId });
    
    // Store event in analytics database
    await this.analyticsDs.getRepository(Event).save({
      userId: user?.id,
      event,
      timestamp: new Date(),
    });
  }
}

Available functions for managing multiple datasources:

| Function | Description | |----------|-------------| | createNamedTypeOrmProvider(name, options) | Create a named provider | | getDataSourceToken(name) | Get injection token for a named DataSource | | getEntityManagerToken(name) | Get injection token for a named EntityManager | | getTypeOrmProvider(name) | Get a registered provider by name | | getAllTypeOrmProviders() | Get all registered providers | | initializeAllTypeOrmProviders() | Initialize all registered providers | | destroyAllTypeOrmProviders() | Close all connections |

Testing

Using SQLite for Tests

import { createTypeOrmProvider } from '@riktajs/typeorm';

const testProvider = createTypeOrmProvider({
  type: 'better-sqlite3',
  database: ':memory:',
  synchronize: true,
  entities: [User, Post],
});

beforeAll(async () => {
  await testProvider.onProviderInit();
});

afterAll(async () => {
  await testProvider.onProviderDestroy();
});

Troubleshooting

"DataSource is not initialized"

This error occurs when you try to use the DataSource before it's been initialized. Make sure:

  1. Your service is decorated with @Injectable()
  2. You're using @Autowired(TYPEORM_DATA_SOURCE) to inject the DataSource
  3. You've provided dataSourceOptions when creating the TypeORM provider
  4. The TypeORM provider is included in the providers array when creating your Rikta app

"No metadata for Entity was found"

This error means TypeORM doesn't know about your entity. Make sure:

  1. You've registered the entity in the entities array of dataSourceOptions
  2. You're importing the entity file before using it
  3. The entity class is decorated with @Entity()
// ✅ Correct
const typeormProvider = createTypeOrmProvider({
  dataSourceOptions: {
    type: 'postgres',
    // ... other options
    entities: [User, Post, Comment], // Register your entities here
  },
});

Connection Refused

Check your database configuration:

// Verify your connection details
const typeormProvider = createTypeOrmProvider({
  dataSourceOptions: {
    type: 'postgres',
    host: 'localhost', // Is this correct?
    port: 5432,        // Is the port correct?
    username: 'admin', // Valid credentials?
    password: 'secret',
    database: 'myapp', // Does this database exist?
  },
});

Schema Synchronization Issues

⚠️ Warning: Never use synchronize: true in production! Use migrations instead.

# Generate a migration
npx typeorm migration:generate -d ./data-source.ts ./migrations/CreateUsers

# Run migrations
npx typeorm migration:run -d ./data-source.ts

API Reference

TypeOrmProvider

| Method | Description | |--------|-------------| | onProviderInit() | Lifecycle hook - initializes the DataSource | | onProviderDestroy() | Lifecycle hook - closes the DataSource | | getDataSource() | Returns the initialized DataSource | | getEntityManager() | Returns the EntityManager | | isConnected() | Returns true if connected |

TypeOrmConfigProvider

| Property | Type | Description | |----------|------|-------------| | type | DatabaseType | Database type | | host | string? | Database host | | port | number? | Database port | | username | string? | Username | | password | string? | Password | | database | string? | Database name | | synchronize | boolean | Schema sync | | logging | boolean | Query logging |

| Method | Description | |--------|-------------| | toConfig() | Returns a TypeOrmConfig object | | isFileBased() | Returns true for SQLite | | getConnectionString() | Returns connection URL |

License

MIT