Faker
Faker generates plausible-looking fake data: names, addresses, emails, company names, credit card numbers, lorem text, dates, and a few hundred other things. You create one generator with Faker() and call a method named after what you want, so fake.name() returns 'Lucy Cechtelar' and fake.address() returns a street address that reads like a real one. The data is grouped into providers you can extend or replace, and most of it is localized: pass a locale like 'ja_JP' or 'it_IT' and you get names and addresses appropriate to that country. It ships a pytest fixture, a command line tool, and integrations with factory_boy, and it is the direct port of the PHP, Ruby, and Perl libraries of the same name.
The obvious choice for seeding databases, building demo data, and filling in the fields your tests do not care about, with locale coverage nothing else in Python matches. Keep it out of your assertions and away from your production anonymization pipeline, and pin the exact version if anything downstream depends on seeded output.
Use it if
- You need to fill a development or staging database with enough realistic rows that pagination, sorting, and layout bugs actually show up, which a thousand rows of 'test1' will never surface
- Your UI needs to survive real-world name and address shapes: apostrophes, accents, long German street names, Japanese characters, and multi-line addresses that break fixed-width columns
- You are writing factory_boy or polyfactory factories and want the fields you do not assert on to be filled with something sensible instead of hardcoded strings
- You need throwaway values in a script (a demo dataset, a load-test payload, sample CSV or JSON) and do not want to hand-type them
- You want reproducible fake data in tests: Faker.seed(4321) makes the whole suite deterministic without giving up variety
- You are asserting on the generated values: random data in assertions is how you get a test that fails once a month because a name contained an apostrophe or a date landed on a leap day, and the honest fix is explicit fixtures for anything the test checks
- You snapshot the output: the docs state plainly that seeded results are not guaranteed consistent across patch versions because datasets keep changing, so a snapshot test against Faker output requires pinning the exact patch number and re-recording on every bump
- You think it anonymizes production data: Faker replaces values one at a time with no memory, so the same customer gets a different name in every table, referential integrity dies, and the statistical distribution of your real data is gone; you need a purpose-built masking tool with consistent pseudonymization
- You need data that satisfies your schema's constraints: Faker knows nothing about your foreign keys, uniqueness rules, or valid state transitions, and .unique is a retry loop that eventually raises UniquenessException and holds every seen value in memory
- You want a locale you are not sure is covered: the factory silently falls back to en_US when a localized provider is missing, so you can ship a 'localized' demo dataset that is quietly full of American addresses
- You want property-based testing: Faker draws plausible values, not adversarial ones, so it will never find the empty string, the surrogate pair, or the off-by-one boundary that hypothesis is designed to hunt down
Setup reality
pip install Faker is one pure-Python package with no dependencies beyond tzdata on Windows, and Python 3.10 or newer. The friction shows up later. Instantiating Faker() imports and wires up every provider for the locale, which is slow enough that you want one module-level instance rather than one per test; passing a list of locales multiplies that cost. Seeding is the part people get wrong: Faker.seed() is a class method that seeds the shared random instance for every generator in the process, while fake.seed_instance() gives that one generator its own random.Random. If you use the bundled pytest plugin, do not call Faker.seed() yourself; override the faker_seed fixture instead, or the plugin's own reseeding per test will fight you. Also pin the version tightly. The project's own note is that datasets change between patch releases, so seeded output is not a stable contract.
Patterns
Create a generator and pull valuesbasic-generation
from faker import Faker
fake = Faker()
fake.name() # 'Jason Brown'
fake.email() # 'daniellewilson@example.net'
fake.safe_email() # 'dickersonbrenda@example.com'
fake.address() # '426 Jordy Lodge\nCartwrightshire, SC 88120-6700'
fake.company() # 'Kutch, Bergstrom and Runolfsson'Build one Faker() at module level and reuse it; constructing it loads every provider and is slow enough to notice in a large test suite. Use safe_email(), safe_domain_name(), and safe_phone_number() for anything that might escape into a real system, since email() can hand you a live domain like gmail.com.
Make generated data deterministicseed-for-reproducibility
from faker import Faker
Faker.seed(4321) # class method: seeds the shared RNG for every generator
fake = Faker()
fake.name() # same value on every run of this version
other = Faker()
other.seed_instance(4321) # this generator only, its own random.RandomFaker.seed() is process-global, so one test calling it changes what every other test sees and makes test order matter. Prefer seed_instance() for isolation. Neither protects you across Faker upgrades: the docs say seeded output can change on a patch bump, so pin the exact version if you depend on specific values.
Generate localized data, including multi-localelocales
from faker import Faker
jp = Faker('ja_JP')
jp.name() # '斎藤 真綾'
multi = Faker(['it_IT', 'ja_JP', 'en_US'])
multi.name() # picks a locale at random per call
multi['ja_JP'].name() # force one locale
multi.locales # ['it_IT', 'ja_JP', 'en_US']When a locale has no provider for the method you called, Faker falls back to en_US without warning, so a 'localized' dataset can be quietly full of US addresses. Check the provider list for your locale before trusting it. Multi-locale generators cost more to build and pick a locale at random per call, not per instance.
Guarantee values do not repeatunique-values
from faker import Faker
fake = Faker()
names = [fake.unique.first_name() for _ in range(50)]
assert len(set(names)) == 50
fake.unique.clear() # forget everything seen so far
# small value spaces blow up:
# [fake.unique.boolean() for _ in range(3)] -> UniquenessExceptionThis is a retry loop, not a reservation system: it keeps every returned value in memory for the life of the instance and raises UniquenessException after a fixed number of failed attempts. On a small pool (booleans, a short enum, first names at scale) the birthday paradox hits sooner than you expect. Call clear() between tests or memory grows all run.
Use the bundled pytest fixturepytest-fixture
# conftest.py
import pytest
@pytest.fixture(scope='session', autouse=True)
def faker_session_locale():
return ['en_US']
@pytest.fixture(scope='function', autouse=True)
def faker_seed():
return 12345
# test_users.py
def test_signup(faker):
user = create_user(name=faker.name(), email=faker.safe_email())
assert user.idFaker ships the plugin, so there is nothing to install or register. The faker fixture is reseeded per test from faker_seed, which means every test gets the same values unless you vary the seed; that is deterministic but also means two tests can collide on a supposedly unique email. Do not also call Faker.seed() in your code, or the two seeding paths fight.
Add your own domain-specific fakecustom-provider
from faker import Faker
from faker.providers import BaseProvider
class CommerceProvider(BaseProvider):
def sku(self) -> str:
return 'SKU-' + self.numerify('####')
fake = Faker()
fake.add_provider(CommerceProvider)
fake.sku() # 'SKU-3829'Inside a provider, use self.numerify, self.lexify, self.bothify, and self.random_element rather than the random module, so your provider honors the seed like everything else. add_provider affects only that instance; register it in a fixture if you want it everywhere.
Pick from your own list of valuesdynamic-provider
from faker import Faker
from faker.providers import DynamicProvider
roles = DynamicProvider(provider_name='role', elements=['dev', 'ops', 'analyst'])
fake = Faker()
fake.add_provider(roles)
fake.role() # 'ops'This is the shortcut when you just need a weighted-free random choice from a fixed list and do not want a whole class. For a one-off, fake.random_element(elements=('dev', 'ops')) does the same thing inline.
Generate values matching a formatpatterned-strings
from faker import Faker
fake = Faker()
fake.bothify(text='??-####', letters='ABC') # 'CA-5583'
fake.lexify('???') # 'szq'
fake.numerify('###-###') # '010-472'
fake.pystr_format('user_{{random_int}}') # 'user_4821'? becomes a letter, # becomes a digit, and % becomes a nonzero digit. This is how you fake order numbers, license plates, and internal ID formats without writing a provider. Nothing enforces uniqueness here; wrap it in fake.unique if you need that.
Generate dates and numbers in a rangedates-and-numbers
from faker import Faker
fake = Faker()
fake.date_between(start_date='-30y', end_date='today') # datetime.date(2007, 12, 1)
fake.date_time_between(start_date='-1y', tzinfo=None) # naive datetime
fake.pyint(min_value=1, max_value=10) # 6
fake.pydecimal(left_digits=3, right_digits=2, positive=True) # Decimal('771.03')Date methods return naive datetimes unless you pass tzinfo, which will bite you the moment the value reaches a timezone-aware ORM column. The relative-date strings ('-30y', '+2d') are parsed by Faker itself and are the easiest way to keep generated dates inside a business-valid window.
Emit whole rows and documentsbulk-structured-data
from faker import Faker
fake = Faker()
fake.profile(fields=['name', 'ssn', 'mail'])
# {'ssn': '006-89-3687', 'name': 'Stephen Garcia', 'mail': 'lloydandrew@gmail.com'}
fake.json(data_columns={'id': 'pyint', 'n': 'name'}, num_rows=1)
# '{"id": 8995, "n": "Ricardo Baker"}'
rows = [{'name': fake.name(), 'email': fake.safe_email()} for _ in range(1000)]profile() and json() are convenient for a quick dump but slow per call because they generate many fields at once; for large seeding runs a plain comprehension over the specific methods you need is noticeably faster. Note the mail field in profile() can use real provider domains.
Wire Faker into factory_boy factoriesfactory-boy-integration
import factory
from myapp.models import Book
class BookFactory(factory.Factory):
class Meta:
model = Book
title = factory.Faker('sentence', nb_words=4)
author_name = factory.Faker('name')
published = factory.Faker('date_between', start_date='-5y', end_date='today')factory.Faker is lazy: it calls the provider when the object is built, not when the class is defined, which is what keeps every instance different. Passing fake.name() directly instead would freeze one value into the class and give every object the same author.
Generate values from the shellcommand-line
faker address
faker -l de_DE address
faker -r 3 -s ';' name
faker profile ssn,birthdate
faker -i faker_credit_score credit_score_fullInstalled as a console script, so it is the fastest way to eyeball what a provider actually returns before writing code. -i takes the import path of the package containing your provider class, not the class itself, which is the flag people get wrong first.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| factory-boy | PyPI | You need whole model objects with relationships and sequences, not loose values; it already integrates Faker for the individual fields. |
| mimesis | PyPI | Generation speed matters (bulk seeding millions of rows) and you want a schema-based API with stricter typing. |
| polyfactory | PyPI | Your models are already pydantic, attrs, or dataclasses and you want factories derived from the type annotations automatically. |
| hypothesis | PyPI | You are testing behavior rather than filling a database, and you want a library that actively searches for inputs that break your code. |