@nestbolt/settings
Quick Start
Set up the module, write your first setting, and read it back in under five minutes.
This guide walks you through the minimal setup to read and write database-backed settings.
1. Register the Module
Add SettingsModule.forRoot() to your root module. The module is registered globally, so you only need to import it once:
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { SettingsModule } from "@nestbolt/settings";
@Module({
imports: [
TypeOrmModule.forRoot({
type: "postgres",
// ... your database config
autoLoadEntities: true,
synchronize: true,
}),
SettingsModule.forRoot(),
],
})
export class AppModule {}SettingsModule registers SettingEntity via TypeOrmModule.forFeature(...) internally, so when you use autoLoadEntities, the table is picked up automatically.
2. Inject the Service
Inject SettingsService anywhere you need to read or write settings:
import { Injectable } from "@nestjs/common";
import { SettingsService } from "@nestbolt/settings";
@Injectable()
export class AppConfigService {
constructor(private readonly settings: SettingsService) {}
}3. Write a Setting
Use set(key, value, options?). The type is inferred from the value when you don't pass options.type:
await this.settings.set("app.name", "Nestbolt"); // type: "string"
await this.settings.set("app.port", 3000); // type: "number"
await this.settings.set("app.debug", true); // type: "boolean"
await this.settings.set("mail", { host: "smtp", port: 587 }); // type: "json"Pass options.group to tag a setting for later filtering with service.group(name), and options.description for a human-readable note:
await this.settings.set("mail.host", "smtp.example.com", {
group: "mail",
description: "Outgoing SMTP server hostname",
});set() runs inside a transaction and uses INSERT ... ON CONFLICT(key) DO UPDATE, so two concurrent setters on the same key produce a single row -- not a UNIQUE violation.
4. Read a Setting
Use get(key, defaultValue?) for an optional read, or getOrFail(key) to throw SettingNotFoundException when the key is missing:
const name = await this.settings.get<string>("app.name");
const port = await this.settings.get<number>("app.port", 3000); // default if missing
const debug = await this.settings.getOrFail<boolean>("app.debug"); // throws if missingThe type column on the entity is honored on read: numbers come back as number, booleans as boolean, JSON as the parsed object, strings as string.
Reads are cached in-memory for cacheTtl ms (default 60_000). Subsequent reads of the same key skip the database until the entry expires or the key is mutated via set() / forget().
5. Check, Delete, List
await this.settings.has("app.name"); // true | false
await this.settings.forget("app.name"); // delete
const allSettings = await this.settings.all(); // Record<string, unknown>
const mailSettings = await this.settings.group("mail"); // group filterforget() runs inside a transaction and emits settings.deleted (when an event emitter is wired up) -- but only if the key actually existed.
6. Inject a Setting Directly with @Setting()
When a setting has been pre-registered in defaults, you can inject its value straight into a constructor:
import { SettingsModule, Setting } from "@nestbolt/settings";
@Module({
imports: [
SettingsModule.forRoot({
defaults: [
{ key: "app.name", value: "Nestbolt", type: "string" },
],
}),
],
})
export class AppModule {}
@Injectable()
export class GreeterService {
constructor(@Setting("app.name") private readonly appName: string) {}
greet() {
return `Hello from ${this.appName}!`;
}
}@Setting(key) resolves to a SETTING_<key> provider that the module creates for each entry in defaults. The provider calls service.get(key, defaultValue) once at construction time, so the injected value reflects whatever's in the database (or the seeded default if the key was missing).
7. Disable the Cache (Optional)
For test environments or when you need strict read-after-write consistency across processes, set cacheTtl: 0:
SettingsModule.forRoot({
cacheTtl: 0,
});With caching off, every get() / getOrFail() / has() hits the database.
Next Steps
- Configuration --
forRoot,forRootAsync, and module-level options. - Decorator --
@Setting(key)reference and validation rules. - Service -- the full
SettingsServiceAPI and the cache. - Seeding -- how
defaultspopulate the database on init. - Events -- listen to
settings.created,settings.updated,settings.deleted.