---
title: "Generate Product Slugs Automatically: Complete 2026 Guide"
slug: "generate-product-slugs-automatically"
published: "2026-01-24"
updated: "2026-02-22"
categories:
  - "Payload"
tags:
  - "generate product slugs"
  - "product slug generation"
  - "Payload job generateProductSlugs"
  - "i18n slugs"
  - "URL-friendly slugs"
  - "formatSlug.ts"
  - "Payload CMS"
  - "PostgreSQL migration"
  - "API endpoint"
  - "backfill missing slugs"
llm-intent: "how-to"
audience-level: "intermediate"
llm-purpose: "Generate product slugs fast with a Payload job that backfills missing slugs across sl/en/ru; run via API or Payload UI and apply migration steps to…"
llm-prereqs:
  - "Payload CMS"
  - "Node.js"
  - "PostgreSQL"
  - "pnpm"
  - "curl"
  - "Payload Admin UI"
---

**Summary Triples**
- (Generate Product Slugs Automatically: Complete 2026 Guide, expresses-intent, how-to)
- (Generate Product Slugs Automatically: Complete 2026 Guide, covers-topic, generate product slugs)
- (Generate Product Slugs Automatically: Complete 2026 Guide, provides-guidance-for, Generate product slugs fast with a Payload job that backfills missing slugs across sl/en/ru; run via API or Payload UI and apply migration steps to…)

### {GOAL}
Generate product slugs fast with a Payload job that backfills missing slugs across sl/en/ru; run via API or Payload UI and apply migration steps to…

### {PREREQS}
- Payload CMS
- Node.js
- PostgreSQL
- pnpm
- curl
- Payload Admin UI

### {STEPS}
1. Confirm prerequisites and job runner setup
2. Inspect product documents and locale fields
3. Generate URL-friendly slugs per locale
4. Implement the generateProductSlugs job handler
5. Register the API endpoint and trigger
6. Create and run database migration
7. Queue the job and monitor logs
8. Resolve conflicts and extend to collections

<!-- llm:goal="Generate product slugs fast with a Payload job that backfills missing slugs across sl/en/ru; run via API or Payload UI and apply migration steps to…" -->
<!-- llm:prereq="Payload CMS" -->
<!-- llm:prereq="Node.js" -->
<!-- llm:prereq="PostgreSQL" -->
<!-- llm:prereq="pnpm" -->
<!-- llm:prereq="curl" -->
<!-- llm:prereq="Payload Admin UI" -->

# Generate Product Slugs Automatically: Complete 2026 Guide
> Generate product slugs fast with a Payload job that backfills missing slugs across sl/en/ru; run via API or Payload UI and apply migration steps to…
Matija Žiberna · 2026-01-24

This guide explains how to use the automated product slug generation system to populate missing slugs for all products across all locales (Slovenian, English, Russian).

## Overview

The slug generation task automatically creates URL-friendly slugs for products based on their titles. It:

- **Generates slugs from titles**: Uses the same logic as manual slug creation (`src/utilities/formatSlug.ts`)
- **Respects existing slugs**: Only generates slugs for products/locales that don't have one yet
- **Handles all locales**: Generates localized slugs for `sl`, `en`, and `ru` based on their respective titles
- **Safe operation**: Never overwrites existing slugs

## How It Works

The slug generation process:

1. Fetches all products from the database with all locales
2. For each product, checks each locale (`sl`, `en`, `ru`)
3. If a slug is missing for that locale:
   - Gets the product title for that locale
   - Generates a URL-friendly slug using the same formatting rules as manual entry
   - Updates only that specific locale's slug field
4. Provides detailed logging and error reporting

### Slug Format

Slugs are formatted according to these rules:

- Spaces replaced with hyphens (`-`)
- Non-word characters removed (except hyphens and slashes)
- Converted to lowercase

**Example transformations:**

- `"Goveje meso"` → `"goveje-meso"`
- `"Fresh Chicken Breast"` → `"fresh-chicken-breast"`
- `"Свежая курица"` → `"kurица"` (Cyrillic handled appropriately)

## Running the Slug Generation Job

### Option 1: Via API Endpoint

Queue the job via HTTP:

```bash
curl -X POST http://localhost:3000/api/generate-product-slugs \
  -H "Authorization: Bearer YOUR_PAYLOAD_API_KEY" \
  -H "Content-Type: application/json"
```

This will return a job ID:

```json
{
  "success": true,
  "jobId": "12345",
  "message": "Product slug generation job queued successfully"
}
```

### Option 2: Via Payload Admin UI

1. Go to the Payload admin panel
2. Navigate to **Jobs** in the sidebar
3. Find the job with task type `generateProductSlugs`
4. Click **Run** to execute it

### Checking Job Status

Use the GET endpoint with your job ID:

```bash
curl "http://localhost:3000/api/generate-product-slugs?jobId=12345" \
  -H "Authorization: Bearer YOUR_PAYLOAD_API_KEY"
```

Response includes:

```json
{
  "jobId": "12345",
  "status": "completed",
  "result": {
    "success": true,
    "totalDocuments": 50,
    "totalSlugsGenerated": 87,
    "errors": []
  }
}
```

## Implementation Details

### Files Created

1. **Job Handler** (`src/payload/jobs/tasks/generateProductSlugs.ts`)
   - Main logic for slug generation
   - Handles all locales independently
   - Includes error handling and logging

2. **API Endpoint** (`src/app/api/generate-product-slugs/route.ts`)
   - HTTP trigger for the job
   - Status checking endpoint
   - Basic authentication

3. **Config Registration** (updated `payload.config.ts`)
   - Registered as a Payload job task
   - Label: "Generate Product Slugs (from titles)"
   - No input parameters needed

### Database Migration Required

After adding the job task to the config, you need to create and run a database migration:

```bash
# Create migration
pnpm run payload migrate:create

# Run migration
pnpm run payload migrate
```

This updates the PostgreSQL enum for job task slugs to include `generateProductSlugs`.

## Examples

### Example 1: New Product with Only Slovenian Title

**Before:**

```json
{
  "title": {
    "sl": "Goveje meso",
    "en": "Beef Meat",
    "ru": "Говядина"
  },
  "slug": "goveje-meso" // Only Slovenian slug exists (string format)
}
```

**After running job:**

```json
{
  "title": {
    "sl": "Goveje meso",
    "en": "Beef Meat",
    "ru": "Говядина"
  },
  "slug": {
    "sl": "goveje-meso",
    "en": "beef-meat",
    "ru": "govyadina"
  }
}
```

### Example 2: Product with Some Missing Slugs

**Before:**

```json
{
  "slug": {
    "sl": "svinje-meso",
    "en": "" // Empty English slug
    // Russian slug missing entirely
  }
}
```

**After running job:**

```json
{
  "slug": {
    "sl": "svinje-meso", // Unchanged
    "en": "pork-meat", // Generated from English title
    "ru": "svinina" // Generated from Russian title
  }
}
```

## Logs and Debugging

The job provides detailed logging:

```
=== PRODUCT SLUG GENERATION JOB STARTED ===
Found 50 product documents

=== Processing Product ID: 123 ===
Product 123 already has slug for locale sl, skipping
Generating slug for product 123 (en): "Beef Meat" -> "beef-meat"
Successfully generated slug for product 123 (en): beef-meat
Generating slug for product 123 (ru): "Говядина" -> "govyadina"
Successfully generated slug for product 123 (ru): govyadina

=== PRODUCT SLUG GENERATION COMPLETED ===
Generated 87 slugs across 50 products
```

## Safety Features

1. **Never overwrites existing slugs**: If a slug already exists for a locale, it's skipped
2. **Per-locale isolation**: Each locale is processed independently
3. **Error isolation**: If one product/locale fails, others continue processing
4. **Detailed error reporting**: All errors are logged and returned in the result

## When to Use This

Use this task when:

- You have products with missing slugs in some locales
- You've imported products without generating slugs
- You've added new locale support and need to backfill slugs
- You want to ensure all products have consistent, URL-friendly identifiers

## Extending for Other Collections

This pattern can be adapted for other collections (Collections, Recipes, etc.) by:

1. Copying the job handler and changing the collection name
2. Adjusting the field names (if not using `title` and `slug`)
3. Registering the new task in `payload.config.ts`
4. Creating a corresponding API endpoint

## Troubleshooting

**Problem**: Job queues but never runs

**Solution**: Make sure you have a job runner process active:

```bash
curl -X POST http://localhost:3000/api/payload-jobs/run \
  -H "Authorization: Bearer YOUR_CRON_SECRET"
```

---

**Problem**: Slugs not generating for a specific locale

**Solution**: Check that the product has a title in that locale. The job logs will show:

```
Product 123 has no title for locale en, skipping slug generation
```

---

**Problem**: "Duplicate slug" error

**Solution**: The job doesn't handle slug uniqueness conflicts. Ensure your titles are unique per locale, or manually adjust conflicting slugs before running the job.

## Related

- [Automating Payload Translations with OpenAI](./automating-payload-translations-with-openai.md) - Similar pattern for translating content
- `src/utilities/formatSlug.ts` - Core slug formatting logic
- `src/fields/slug.ts` - Slug field definition and hooks