@nestbolt/settings
v0.1.0
Published
Database-backed key-value application settings for NestJS with TypeORM, typed access, caching, and auto-seeding.
Maintainers
Readme
This package provides a database-backed settings store for NestJS that lets you manage application configuration at runtime with typed access, in-memory caching, and auto-seeding.
Once installed, using it is as simple as:
const appName = await settingsService.get<string>("app.name", "MyApp");
await settingsService.set("app.theme", "dark");Table of Contents
- Installation
- Quick Start
- Module Configuration
- Using the Service
- Setting Types
- Setting Groups
- Caching
- Auto-Seeding
- Events
- Configuration Options
- Testing
- Changelog
- Contributing
- Security
- Credits
- License
Installation
Install the package via npm:
npm install @nestbolt/settingsOr via yarn:
yarn add @nestbolt/settingsOr via pnpm:
pnpm add @nestbolt/settingsPeer Dependencies
This package requires the following peer dependencies, which you likely already have in a NestJS project:
@nestjs/common ^10.0.0 || ^11.0.0
@nestjs/core ^10.0.0 || ^11.0.0
@nestjs/typeorm ^10.0.0 || ^11.0.0
typeorm ^0.3.0
reflect-metadata ^0.1.13 || ^0.2.0Optional:
@nestjs/event-emitter ^2.0.0 || ^3.0.0Quick Start
- Register the module in your
AppModule:
import { SettingsModule } from "@nestbolt/settings";
@Module({
imports: [
TypeOrmModule.forRoot({
/* ... */
}),
SettingsModule.forRoot({
defaults: [
{ key: "app.name", value: "MyApp", type: "string" },
{ key: "app.perPage", value: 25, type: "number" },
],
}),
],
})
export class AppModule {}- Inject and use the service:
import { SettingsService } from "@nestbolt/settings";
@Injectable()
export class AppService {
constructor(private readonly settings: SettingsService) {}
async getAppName(): Promise<string> {
return this.settings.get<string>("app.name", "Default");
}
async updateTheme(theme: string): Promise<void> {
await this.settings.set("app.theme", theme, { group: "appearance" });
}
}Module Configuration
Static Configuration (forRoot)
SettingsModule.forRoot({
cacheTtl: 60000, // 1 minute cache (default)
autoSeed: true, // Auto-seed defaults (default: true)
defaults: [
{ key: "app.name", value: "MyApp", type: "string", group: "app" },
{ key: "app.debug", value: false, type: "boolean", group: "app" },
{
key: "mail.from",
value: "[email protected]",
type: "string",
group: "mail",
},
],
});Async Configuration (forRootAsync)
SettingsModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
cacheTtl: config.get("SETTINGS_CACHE_TTL", 60000),
defaults: [
{ key: "app.name", value: config.get("APP_NAME"), type: "string" },
],
}),
});The module is registered as global — SettingsService is available everywhere without re-importing.
Using the Service
Inject SettingsService into any service or controller:
| Method | Returns | Description |
| --------------------------- | ------------------------------ | ------------------------------------------------------------------- |
| get<T>(key, default?) | Promise<T> | Get a setting value, returns default if not found |
| getOrFail<T>(key) | Promise<T> | Get a setting value, throws SettingNotFoundException if not found |
| set(key, value, options?) | Promise<SettingEntity> | Create or update a setting |
| has(key) | Promise<boolean> | Check if a setting exists |
| forget(key) | Promise<void> | Delete a setting |
| all() | Promise<Record<string, any>> | Get all settings as a key-value map |
| group(name) | Promise<Record<string, any>> | Get all settings in a group |
| flushCache() | void | Clear the in-memory cache |
Setting Types
Settings support four types with automatic casting:
| Type | Stored As | Cast To |
| --------- | --------- | ----------------------------------- |
| string | text | string |
| number | text | Number() |
| boolean | text | true/"1" = true, else false |
| json | text | JSON.parse() |
await settings.set("app.port", 3000, { type: "number" });
await settings.set("app.debug", true, { type: "boolean" });
await settings.set("app.config", { theme: "dark" }, { type: "json" });If no type is specified, it is inferred from the value.
Setting Groups
Organize settings by group for easy retrieval:
await settings.set("mail.host", "smtp.example.com", { group: "mail" });
await settings.set("mail.port", "587", { group: "mail" });
const mailSettings = await settings.group("mail");
// { 'mail.host': 'smtp.example.com', 'mail.port': '587' }Caching
Settings are cached in memory with a configurable TTL (default: 60 seconds). Set cacheTtl: 0 to disable caching.
The cache is automatically invalidated when you call set() or forget(). Use flushCache() to manually clear it.
Auto-Seeding
When autoSeed is enabled (default), the module seeds any defaults that don't already exist in the database during initialization. Existing settings are never overwritten.
Events
When @nestjs/event-emitter is installed, the following events are emitted:
| Event | Payload |
| ------------------ | ----------------------------------- |
| settings.created | { key, value, type, group } |
| settings.updated | { key, oldValue, newValue, type } |
| settings.deleted | { key, lastValue } |
Configuration Options
| Option | Type | Default | Description |
| ---------- | --------------------- | ----------- | -------------------------------------- |
| defaults | SettingDefinition[] | undefined | Default settings to seed on init |
| cacheTtl | number | 60000 | Cache TTL in ms (0 to disable) |
| autoSeed | boolean | true | Auto-seed defaults if keys don't exist |
Testing
npm testRun tests in watch mode:
npm run test:watchGenerate coverage report:
npm run test:covChangelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security-related issues, please report them via GitHub Issues with the security label instead of using the public issue tracker.
License
The MIT License (MIT). Please see License File for more information.
