Skip to main content

Python Slugify

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

CI PyPI

Quickstart

9+ releases ship the modern algorithm. Legacy behavior remains the default; use algorithm='modern' for the latest rules. 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

# Use the modern algorithm for the latest rules.
assert slugify("C'est déjà l'été.", algorithm='modern') == 'c-est-deja-l-ete'
assert slugify('影師嗎', backend='text-unidecode', algorithm='modern') == 'ying-shi-ma'
assert slugify('影師嗎', allow_unicode=True, algorithm='modern') == '影師嗎'

# Calling slugify() without algorithm uses the legacy pipeline (the old default),
# kept unchanged for backward compatibility.
assert slugify("C'est déjà l'été.") == 'c-est-deja-l-ete'
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 9+ releases. 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.1

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.1
File Size Uploaded
python_slugify-9.1.1.tar.gz 64.1 kB Details

Built distribution (wheel)

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

Total release size: 79.9 kB

Release files / python_slugify-9.1.1.tar.gz

Download URL python_slugify-9.1.1.tar.gz
Size 64.1 kB
Tags Source
SHA-256 checksum
How to use checksums
db48547ed6d43072af59c86c3bc80bfc3c6f4e88c130c99de11775d721a574b8
BLAKE2b-256 checksum
How to use checksums
a7a6c1c00c174f50edd6e9d244d97c6377191fd1f93fd76841f9e3d46073be2f
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.1-py3-none-any.whl

Download URL python_slugify-9.1.1-py3-none-any.whl
Size 15.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6db0d9480b22a8867e2dbd725e0eea28e7893ee1dc00bdae467b345ad0eafafb
BLAKE2b-256 checksum
How to use checksums
b1869a0b95c7e0db6f8ed85c7d726da4bf4853b25f0de244f075e29b91fd167b
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

9.1.1 This release

2 release files

9.1.0

2 release files

9.0.0

2 release files

8.0.4

2 release files

8.0.3

2 release files

8.0.2

2 release files

8.0.1

2 release files

8.0.0

2 release files

7.0.0

2 release files

6.1.2

2 release files

6.1.1

2 release files

6.1.0

2 release files

6.0.1

2 release files

6.0.0

2 release files

5.0.2

2 release files

5.0.1

2 release files

5.0.0

2 release files

4.0.1

1 release file

4.0.0

1 release file

3.0.6

1 release file

3.0.5

1 release file

3.0.4

1 release file

3.0.3

1 release file

3.0.2

1 release file

3.0.1

1 release file

3.0.0

1 release file

2.0.1

1 release file

2.0.0

1 release file

1.2.6

1 release file

1.2.5

1 release file

1.2.4

2 release files

1.2.3

1 release file

1.2.2

1 release file

1.2.1

1 release file

1.2.0

1 release file

1.1.4

1 release file

1.1.3

1 release file

1.1.2

1 release file

1.0.2

1 release file

0.1.1

0.1.0

1 release file

0.0.9

1 release file

0.0.8

1 release file

0.0.7

1 release file

0.0.6

1 release file

0.0.5

1 release file

0.0.4

1 release file

0.0.3

1 release file

0.0.2

1 release file

0.0.1

1 release file

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