@nestbolt/sluggable
Configuration
All SluggableModule.forRoot() and forRootAsync() options explained.
forRoot Options
SluggableModule.forRoot() accepts an optional SluggableModuleOptions object to set global defaults:
SluggableModule.forRoot({
separator: "-",
maxLength: 255,
lowercase: true,
transliterate: true,
onUpdate: "keep",
suffixSeparator: "-",
})| Option | Type | Default | Description |
|---|---|---|---|
separator | string | "-" | Word separator in generated slugs |
maxLength | number | 255 | Maximum slug length. Truncates at word boundaries |
lowercase | boolean | true | Whether to lowercase the slug |
transliterate | boolean | true | Transliterate non-Latin characters to ASCII |
transliterator | (input: string) => string | Built-in | Custom transliteration function |
onUpdate | "keep" | "regenerate" | "keep" | Default update behavior for all entities |
suffixSeparator | string | "-" | Separator between base slug and collision suffix |
All options are optional -- calling SluggableModule.forRoot() with no arguments uses all defaults.
forRootAsync
Use forRootAsync() when your configuration depends on other providers (e.g., ConfigService):
import { ConfigModule, ConfigService } from "@nestjs/config";
import { SluggableModule } from "@nestbolt/sluggable";
@Module({
imports: [
ConfigModule.forRoot(),
SluggableModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
maxLength: config.get<number>("SLUG_MAX_LENGTH", 100),
onUpdate: config.get<string>("SLUG_ON_UPDATE", "keep") as "keep" | "regenerate",
}),
}),
],
})
export class AppModule {}forRootAsync Options
| Option | Type | Description |
|---|---|---|
imports | any[] | Modules to import for dependency injection |
inject | any[] | Providers to inject into the factory function |
useFactory | (...args) => SluggableModuleOptions | Factory function that returns the options |
Option Details
separator
Controls the character used between words in the generated slug:
SluggableModule.forRoot({ separator: "_" })
// "Hello World" → "hello_world"
SluggableModule.forRoot({ separator: "-" })
// "Hello World" → "hello-world"This can be overridden per entity via the @Sluggable() decorator.
maxLength
Slugs longer than maxLength are truncated at the last word boundary before the limit:
SluggableModule.forRoot({ maxLength: 20 })
// "This is a very long article title" → "this-is-a-very-long"Truncation never splits a word or leaves a trailing separator.
transliterate
When enabled, non-Latin characters are converted to their ASCII equivalents before slugifying:
// transliterate: true (default)
// "café résumé" → "cafe-resume"
// transliterate: false
// "café résumé" → "caf-rsum"See Transliteration for details on supported character sets and custom transliterators.
onUpdate
Controls the global default for what happens when an entity is updated:
"keep"(default) -- the slug is preserved unless it's empty"regenerate"-- the slug is regenerated from source fields when they change
This can be overridden per entity via the @Sluggable() decorator. See Update Behavior for details.
suffixSeparator
Controls the separator between the base slug and the collision suffix number:
SluggableModule.forRoot({ suffixSeparator: "_" })
// First: "hello-world"
// Collision: "hello-world_1"
SluggableModule.forRoot({ suffixSeparator: "-" })
// First: "hello-world"
// Collision: "hello-world-1"SluggableService API
SluggableService is available via dependency injection after module registration:
@Injectable()
export class MyService {
constructor(private readonly sluggable: SluggableService) {}
}generateSlug(input, overrides?)
Generates a slug from a string without uniqueness checking:
sluggable.generateSlug("Hello World");
// "hello-world"
sluggable.generateSlug("Hello World", { separator: "_", maxLength: 10 });
// "hello_worl"generateUniqueSlug(entityConstructor, slugField, baseSlug, excludeId?)
Generates a unique slug by checking the database for collisions:
const slug = await sluggable.generateUniqueSlug(Post, "slug", "hello-world");
// "hello-world" or "hello-world-1" if collision existsPass excludeId to exclude the current entity during update:
const slug = await sluggable.generateUniqueSlug(Post, "slug", "hello-world", post.id);findBySlug(entityConstructor, slugField, slug)
Finds an entity by its slug value:
const post = await sluggable.findBySlug(Post, "slug", "hello-world");
// Post | nullregenerateSlug(entity, sourceFields, slugField, overrides?)
Regenerates the slug for an entity from its current source field values:
post.title = "New Title";
const newSlug = await sluggable.regenerateSlug(post, ["title"], "slug");
// "new-title"