Skip to main content

Python Slugify

Unicode-aware slug generation for Python, with explicit transliteration choices.

CI PyPI

Quickstart

9.0.0 is available on PyPI. Legacy behavior remains the default; improved rules require algorithm='modern'. See the migration guide before changing persisted URLs or keys.

Install python-slugify, import slugify. Other similarly named distributions are not this package.

python -m pip install --upgrade python-slugify
from slugify import slugify

assert slugify("C'est déjà l'été.") == 'c-est-deja-l-ete'
assert slugify('影師嗎', backend='text-unidecode') == 'ying-shi-ma'
assert slugify('影師嗎', allow_unicode=True) == '影師嗎'
slugify "Hello, world!"
# hello-world
printf 'Café' | python -m slugify --stdin
# cafe
slugify --regex-pattern '[^-a-z0-9_]+' '___This is a test___'
# ___this-is-a-test___

The examples above work with the published 9.0.0 release. Python 3.10 or newer is required.

Python support

Python Release family
2.7–3.5 below 5
3.6 5–6
3.7–3.9 7–8 (check each release's Requires-Python)
3.10+ 9.x

The configured release-9 test matrix covers CPython 3.10–3.14 and PyPy 3.11. Configuration is not proof of a successful run; see local verification. Older applications can stay on a pinned 8.x release rather than upgrading Python or regenerating slugs immediately.

Backends and installation

backend Runtime selection Installation
auto (default) Installed Unidecode first, otherwise text-unidecode Base install includes text-unidecode
text-unidecode Only text-unidecode Included in base install
unidecode Only Unidecode python -m pip install 'python-slugify[unidecode]'
anyascii Only AnyASCII python -m pip install 'python-slugify[anyascii]'

Explicit selection never silently falls back. A missing selected module raises ModuleNotFoundError. Backend imports are lazy; allow_unicode=True bypasses transliteration entirely. Extras add dependencies; they do not remove text-unidecode. The AnyASCII extra does not change the default backend. There is no dependency-free installation extra in this release.

Transliteration is not translation, language detection, or context-sensitive pronunciation. Backends produce different slugs: for example 影師嗎 becomes ying-shi-ma with text-unidecode/Unidecode, but yingshima with AnyASCII. Pin both this package and your explicitly chosen backend for stable persisted identifiers.

API options

The original positional parameters remain in their original order. New options are keyword-only.

slugify(
    text, entities=True, decimal=True, hexadecimal=True,
    max_length=0, word_boundary=False, separator='-', save_order=False,
    stopwords=(), regex_pattern=None, lowercase=True, replacements=(),
    allow_unicode=False, *, replacement_stage='both', backend='auto',
    algorithm='legacy',
)
  • algorithm: 'legacy' is the permanent default, preserving the historical output pipeline. 'modern' explicitly opts into the changes below. Unknown values raise ValueError.

    Note for contributors: the legacy algorithm is frozen. Its behavior and output are intentionally kept as-is for backward compatibility, and we do not accept changes that alter legacy output — please do not open PRs to "fix" or "improve" legacy. All improvements target algorithm='modern'.

  • text: str, or UTF-8 bytes/bytearray (invalid bytes ignored). Other objects raise TypeError.

  • entities, decimal, hexadecimal: independently decode named HTML entities, decimal references, and hexadecimal references. Legacy accepts lowercase x; modern accepts both x and X as specified by HTML. Legacy decodes after transliteration and numeric substitutions are all-or-nothing per reference kind. Modern decodes before transliteration and handles invalid references independently.

  • max_length: legacy budgets internal dashes before separator mapping, so wide separators can exceed the limit. Modern budgets final Python characters, including emitted delimiters. Nonpositive means unlimited for slugify; this is not a byte or grapheme limit.

  • word_boundary: prefer whole words; shorter later words can fill the budget. If none fit, use a hard cut.

  • save_order: with word boundaries, stop at the first oversized word instead of skipping it.

  • separator: literal emitted delimiter; may be empty or multiple characters. Existing dashes also map to this delimiter for compatibility. Modern truncation preserves word characters even when they match the output delimiter.

  • stopwords: iterable of whole normalized, internal dash-separated tokens. Matching is case-insensitive when lowercase=True; stopwords themselves are not transliterated. Legacy case-sensitive membership consumes iterators; modern snapshots them once.

  • regex_pattern: string or compiled regular expression matching disallowed characters, not allowed ones. It overrides default filtering. Empty strings retain historical default-pattern behavior.

  • lowercase: apply str.lower(); false preserves case.

  • replacements: ordered iterable of (old, new) literal string rules. Legacy preserves iterator consumption across passes. Modern materializes outer and inner iterables once so generators behave like lists.

  • replacement_stage: both preserves two passes; pre runs only before normalization; post runs after cleanup and stopword removal, before separator mapping and truncation. Post replacements are not re-sanitized. Replacements need not be idempotent.

  • allow_unicode: retain Unicode word characters after NFKC normalization, not exact original code points; default ASCII mode uses NFKD plus transliteration.

  • backend: select a backend from the table above. Ignored for transliteration in Unicode mode, but still validated.

smart_truncate(string, max_length=0, word_boundary=False, separator=' ', save_order=False) is also public and retains legacy behavior: str.strip(separator) strips a character set, empty separators raise ValueError, zero is unlimited, and negative limits retain slicing semantics. Modern slugify uses a separate private token-budget helper; it does not change this public function.

from slugify import slugify

assert slugify('a'b') == 'ab'  # unchanged default
assert slugify('a'b', algorithm='modern') == 'a-b'
assert slugify('xylophone x', separator='x', max_length=100, algorithm='modern') == 'xylophonexx'

Recipes and boundaries

from slugify import slugify, GERMAN

assert slugify('ÜBER', replacements=GERMAN, replacement_stage='pre') == 'ueber'
assert slugify('a', replacements=[('a', 'aa')]) == 'aaaa'  # legacy two passes
assert slugify('a', replacements=[('a', 'aa')], replacement_stage='pre') == 'aa'
assert slugify('one two three four', max_length=12, word_boundary=True) == 'one-two-four'
assert slugify('one two three four', max_length=12, word_boundary=True, save_order=True) == 'one-two'
assert slugify('a b c', separator='---', max_length=5, algorithm='modern') == 'a---b'
assert slugify('Baby’s shoes', replacements=[('’', '-')], replacement_stage='pre') == 'baby-s-shoes'

CYRILLIC, GERMAN, GREEK, and their combined PRE_TRANSLATIONS are optional substitution lists, not automatically applied locale rules. allow_unicode=True can normalize compatibility jamo, and does not preserve emoji by default. Disable all three entity flags if encoded markup should not be decoded. Empty input, whitespace, or entirely filtered content can yield an empty string; callers choose an appropriate fallback.

Slugs are not guaranteed unique, filesystem-safe on every OS, XML-name-safe, or safe as an entire URL. Choose escaping, reserved-name handling, path validation, and transactional uniqueness for your destination. Custom regexes and post replacements can intentionally introduce punctuation; do not treat this package as a security sanitizer.

Command line

slugify --help and python -m slugify --help describe all options, including --algorithm (default legacy), --backend and --replacement-stage. Use -- before text when supplying multi-valued options:

slugify --stopwords the in a hurry -- the quick brown fox jumps over the lazy dog in a hurry
slugify --replacement-stage pre --replacements 'a->aa' -- a

Development and local release checks

python -m pip install -r dev.requirements.txt
python -m pip install -e '.[unidecode,anyascii]'
python -m pytest
python -m mypy
python tools/check_dist.py
# Full declared interpreter/backend matrix (requires those interpreters):
tox

The artifact check builds and installs both wheel and source archive in temporary environments outside the checkout. It never uploads or tags. Publishing requires a separate maintainer decision; there is no setup.py publish shortcut. See migration and release notes, review and draft replies, and the historical review. Please consult the contribution wiki before proposing changes.

Licensing

python-slugify's own code is MIT licensed. Dependency licenses are separate:

  • text-unidecode: upstream offers the Artistic License or GPL; review the license files for the version you distribute.
  • Unidecode: GPL-licensed; review its upstream license text and version.
  • AnyASCII: ISC-licensed; review its upstream license text and any bundled notices.

The installed package set and the backend used at runtime are different questions. Selecting AnyASCII does not remove text-unidecode from a normal installation. This is factual dependency guidance, not legal advice or a blanket assurance about your application's obligations. Evaluate the actual versions, distribution method, and applicable license terms.

Sponsors

Neekware Inc. — creator of Dojo Workspace, your AI workspace for building, learning, and getting things done.

🚀 Created with Dojo ⛩️

Release files for python-slugify 9.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for python-slugify 9.1.0
File Size Uploaded
python_slugify-9.1.0.tar.gz 63.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for python-slugify 9.1.0
File Interpreter ABI Platform
python_slugify-9.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 79.2 kB

Release files / python_slugify-9.1.0.tar.gz

Download URL python_slugify-9.1.0.tar.gz
Size 63.6 kB
Tags Source
SHA-256 checksum
How to use checksums
3f02e8a0639c61e37eca5a783aae09112796d15d331ee3d5372241b61ee05f1c
BLAKE2b-256 checksum
How to use checksums
d8ca5740963aa82f2c9dd025d71f1b6cce2159545f9e60dcb86a447d1cf92252
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / python_slugify-9.1.0-py3-none-any.whl

Download URL python_slugify-9.1.0-py3-none-any.whl
Size 15.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ab2d1d0e7ad5fa46b3756f0f3fcfb37d6d5baa006ccd1f22c2481a6ab53b8c12
BLAKE2b-256 checksum
How to use checksums
aef1e450f6f6eb1217a6dc5f015589a21566839297920304961a7c2230477837
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

This release
Image

9.1.0 This release

2 release files

Image

9.0.0

2 release files

Image

8.0.4

2 release files

Image

8.0.3

2 release files

Image

8.0.2

2 release files

Image

8.0.1

2 release files

Image

8.0.0

2 release files

Image

7.0.0

2 release files

Image

6.1.2

2 release files

Image

6.1.1

2 release files

Image

6.1.0

2 release files

Image

6.0.1

2 release files

Image

6.0.0

2 release files

Image

5.0.2

2 release files

Image

5.0.1

2 release files

Image

5.0.0

2 release files

Image

4.0.1

1 release file

Image

4.0.0

1 release file

Image

3.0.6

1 release file

Image

3.0.5

1 release file

Image

3.0.4

1 release file

Image

3.0.3

1 release file

Image

3.0.2

1 release file

Image

3.0.1

1 release file

Image

3.0.0

1 release file

Image

2.0.1

1 release file

Image

2.0.0

1 release file

Image

1.2.6

1 release file

Image

1.2.5

1 release file

Image

1.2.4

2 release files

Image

1.2.3

1 release file

Image

1.2.2

1 release file

Image

1.2.1

1 release file

Image

1.2.0

1 release file

Image

1.1.4

1 release file

Image

1.1.3

1 release file

Image

1.1.2

1 release file

Image

1.0.2

1 release file

Image

0.1.1

Image

0.1.0

1 release file

Image

0.0.9

1 release file

Image

0.0.8

1 release file

Image

0.0.7

1 release file

Image

0.0.6

1 release file

Image

0.0.5

1 release file

Image

0.0.4

1 release file

Image

0.0.3

1 release file

Image

0.0.2

1 release file

Image

0.0.1

1 release file

Image Anthropic, PBC Visionary sponsor Image Bloomberg Visionary sponsor Image Hudson River Trading Visionary sponsor Image Meta Visionary sponsor Image NVIDIA Visionary sponsor Image Microsoft Sustainability sponsor Image Depot Continuous Integration Image AWS Cloud computing and Security Sponsor Image Datadog Monitoring Image Fastly CDN Image Google Download Analytics Image Sentry Error logging Image StatusPage Status page