Skip to Content
HeronJS 3.6 with fully support Typescript 6 is released 🎉
OverviewDatasource

Data sources manage database connections in HeronJS. They define how your application connects to systems such as MySQL, PostgreSQL, or Oracle, and make those connections available throughout your modules.


Create a data source configuration

Start by defining a configuration object for each database you want to connect to. This configuration describes the database client, connection credentials, driver, pooling, and optional cluster settings.

PostgreSQL

export const PostgresDatabaseConfiguration = { client: DatabaseClient.KNEX, config: <CommonDatabaseConfig>{ host: process.env.POSTGRES_HOST || 'localhost', port: process.env.POSTGRES_PORT || 5432, user: process.env.POSTGRES_USER || 'root', password: process.env.POSTGRES_PASSWORD || 'root@123', database: process.env.POSTGRES_DATABASE || 'test', pooling: { min: 1, max: 10 }, driver: DatabaseDriver.POSTGRES, cluster: { secondaries: [ { host: 'localhost', port: 5433, }, ], }, }, };

MySQL and MariaDB

export const MySQLDatabaseConfiguration = { client: DatabaseClient.KNEX, config: <CommonDatabaseConfig>{ host: process.env.MYSQL_HOST || 'localhost', port: process.env.MYSQL_PORT || 3306, user: process.env.MYSQL_USER || 'dev', password: process.env.MYSQL_PASSWORD || 'dev@123', database: process.env.MYSQL_DATABASE || 'dev', pooling: { min: 1, max: 10 }, driver: DatabaseDriver.MYSQL, cluster: { secondaries: [ { host: 'localhost', port: 3307, }, ], }, }, };

In both examples:

  • client selects the underlying database client implementation.
  • config contains the connection settings for the driver.
  • pooling controls how many connections can be reused.
  • cluster.secondaries lets you define additional replica connections.

Create a data source class

After defining the configuration, create a class that extends AbstractDataSourceClient. This class becomes the injectable data source used by the rest of the application.

@UseConfig(PostgresDatabaseConfiguration) export class PostgresDatabase extends AbstractDataSourceClient<KnexClient> { constructor() { super(); } context(): DatabaseContext<any> { return this; } }

Here:

  • @UseConfig(...) attaches the configuration object to the data source.
  • AbstractDataSourceClient provides the base behavior for supported database clients.
  • context() exposes the database context that other parts of the application can consume.

Create a custom database client

If you need to work with a database that does not use the built-in data source client, you can implement your own client by extending AbstractDatabaseClient.

@Default() export class CassandraDatabase extends AbstractDatabaseClient<Any> { init(): DatabaseConnector<Any> { return { connect: () => { // database connection behavior }, get: () => { // database instance }, }; } }

Use this pattern when you need full control over how the connection is created and exposed.

Multi-tenant data source

For tenant-aware applications, use AbstractTenancyDataSourceClient instead of the standard data source base class.

@UseConfig(PostgresDatabaseConfiguration) export class PostgresDatabase extends AbstractTenancyDataSourceClient<KnexClient> { constructor() { super(); } }

This allows the data source to resolve connections based on tenant context.

Multi-primary data source

If your deployment uses writable secondary nodes, mark them explicitly in the cluster configuration.

export const PostgresDatabaseConfiguration = { client: DatabaseClient.KNEX, config: <CommonDatabaseConfig>{ host: process.env.POSTGRES_HOST || 'localhost', port: process.env.POSTGRES_PORT || 5432, user: process.env.POSTGRES_USER || 'root', password: process.env.POSTGRES_PASSWORD || 'root@123', database: process.env.POSTGRES_DATABASE || 'test', pooling: { min: 1, max: 10 }, driver: DatabaseDriver.POSTGRES, cluster: { secondaries: [ { host: 'localhost', port: 5433, writable: true, }, ], }, }, };

Set writable: true only when that node should accept write operations.

Set a default data source

Use @Default() when you want a data source to be selected automatically during lookup.

@UseConfig(PostgresDatabaseConfiguration) @Default() export class PostgresDatabase extends AbstractDataSourceClient<KnexClient> { constructor() { super(); } context(): DatabaseContext<any> { return this; } }

This is useful when most of your application should use one primary database without specifying its name each time.

Register data sources in the root module

To make data sources available to the application, register them in the root module with @DataSources(...).

@Module({ imports: [TodosModule], }) @DataSources([MySQLDatabase, PostgresDatabase]) export class AppModule {}

Once registered, the data sources can be injected into providers and services across your modules.

Look up a data source

Use @DatabaseLookup() to inject a registered data source into a provider.

  • @DataSource() resolves the default data source.
  • @DataSource('name') resolves a specific data source by name or token.
import { Provider, Scope } from '@heronjs/common'; @Provider({ scope: Scope.SINGLETON, }) export class TodoProvider { constructor(@DataSource() private readonly db: ModuleDatabase<KnexClient>) {} async findAll() { return ['todo1']; } }

To inject a specific database instead of the default one:

import { Provider, Scope } from '@heronjs/common'; @Provider({ scope: Scope.SINGLETON, }) export class ReportingProvider { constructor( @DataSource('other-database') private readonly db: ModuleDatabase<KnexClient>, ) {} }

Supported decorators

  • @UseConfig attaches a configuration object to a data source.
  • @Default marks a data source as the default lookup target.
  • @DatabaseLookup injects a registered data source into a class.
Last updated on