@faker-js/faker vs Chance.js vs Casual: Test Data Generation in Node.js (2026)
TL;DR
@faker-js/faker is the default choice in 2026 — it's the community-maintained fork of the original faker.js with full TypeScript support, extensive locales, and seeded random generation for reproducible test data. Chance.js is the battle-tested alternative with a clean API focused on probability distributions. Casual is a simpler option for quick fake data without the overhead. For most projects, faker is the right choice.
Key Takeaways
- @faker-js/faker: ~5.8M weekly downloads — TypeScript-native, 60+ locales, seeded random
- chance: ~1.8M weekly downloads — probability-focused, clean API, good for custom distributions
- casual: ~250K weekly downloads — lightweight, minimal API, no TypeScript types
- @faker-js/faker replaced the original unmaintained
fakerpackage in 2022 - Seed your faker for reproducible test data — same seed = same data every run
- Use faker for database seeding, Storybook stories, API mocks, and unit test fixtures
Download Trends
| Package | Weekly Downloads | TypeScript | Locales | Seedable |
|---|---|---|---|---|
@faker-js/faker | ~5.8M | ✅ Native | 60+ | ✅ |
chance | ~1.8M | ✅ @types | 10+ | ✅ |
casual | ~250K | ❌ | Limited | ✅ |
@faker-js/faker
@faker-js/faker is the community-maintained fork with extensive data modules and full TypeScript support.
Basic Data Generation
import { faker } from "@faker-js/faker"
// Person data:
const name = faker.person.fullName() // "John Smith"
const firstName = faker.person.firstName() // "Emily"
const lastName = faker.person.lastName() // "Johnson"
const jobTitle = faker.person.jobTitle() // "Senior Software Engineer"
const bio = faker.person.bio() // "Helping people with their needs."
// Internet:
const email = faker.internet.email() // "emily.johnson@example.com"
const username = faker.internet.username() // "emily_johnson_42"
const url = faker.internet.url() // "https://gentle-llama.net"
const avatar = faker.image.avatar() // "https://avatars.githubusercontent.com/..."
// Numbers and ids:
const id = faker.string.uuid() // "abc123-..."
const nanoid = faker.string.nanoid() // "V1StGXR8_Z5jdHi6B-myT"
const num = faker.number.int({ min: 1, max: 100 })
const float = faker.number.float({ min: 0, max: 1, fractionDigits: 2 })
// Text:
const word = faker.word.noun() // "mountain"
const sentence = faker.lorem.sentence() // "Lorem ipsum dolor sit amet."
const paragraph = faker.lorem.paragraph(3) // Multi-sentence paragraph
// Dates:
const pastDate = faker.date.past() // Date in the past
const recentDate = faker.date.recent({ days: 7 }) // Last 7 days
const futureDate = faker.date.future({ years: 1 }) // Next year
// Commerce:
const price = faker.commerce.price({ min: 1, max: 100 }) // "42.99"
const productName = faker.commerce.productName() // "Ergonomic Chair"
const department = faker.commerce.department() // "Outdoors"
// Location:
const city = faker.location.city() // "New York"
const country = faker.location.country() // "United States"
const zipCode = faker.location.zipCode() // "10001"
const lat = faker.location.latitude()
const lng = faker.location.longitude()
Seeded Generation (Reproducible Test Data)
import { faker } from "@faker-js/faker"
// Set seed for reproducible data:
faker.seed(12345)
const user1 = {
id: faker.string.uuid(),
name: faker.person.fullName(),
email: faker.internet.email(),
}
// Always generates the same output with seed 12345
// Reset seed for random:
faker.seed() // No arg = random seed
// Or create a scoped instance with seed:
const seededFaker = new Faker({ locale: [en], seed: 12345 })
Building Test Fixtures
import { faker } from "@faker-js/faker"
// Factory function pattern:
function createUser(overrides: Partial<User> = {}): User {
return {
id: faker.string.uuid(),
name: faker.person.fullName(),
email: faker.internet.email(),
avatar: faker.image.avatar(),
createdAt: faker.date.past({ years: 2 }),
role: faker.helpers.arrayElement(["admin", "editor", "viewer"] as const),
weeklyDownloads: faker.number.int({ min: 0, max: 10000000 }),
...overrides, // Allow tests to override specific fields
}
}
function createPackage(overrides: Partial<Package> = {}): Package {
const name = faker.internet.domainWord()
return {
id: faker.string.uuid(),
name,
description: faker.lorem.sentences(2),
version: faker.system.semver(),
weeklyDownloads: faker.number.int({ min: 100, max: 25000000 }),
license: faker.helpers.arrayElement(["MIT", "Apache-2.0", "ISC", "GPL-3.0"]),
author: faker.person.fullName(),
publishedAt: faker.date.past({ years: 5 }),
...overrides,
}
}
// Create arrays with unique values:
function createPackages(count: number): Package[] {
return faker.helpers.uniqueArray(
() => createPackage(),
count
)
}
// Test usage:
const testPackage = createPackage({ name: "react", weeklyDownloads: 25000000 })
const testUser = createUser({ role: "admin" })
const packageList = createPackages(10)
Locales
import { faker } from "@faker-js/faker"
import { de, fr, ja, zh_CN } from "@faker-js/faker"
// Locale-specific data:
const germanFaker = new Faker({ locale: [de] })
console.log(germanFaker.location.city()) // "München"
console.log(germanFaker.person.fullName()) // "Hans-Werner Schmidt"
const japaneseFaker = new Faker({ locale: [ja] })
console.log(japaneseFaker.person.fullName()) // "田中 太郎"
// Fallback locales (use base locale for missing data):
import { base } from "@faker-js/faker"
const frenchWithFallback = new Faker({ locale: [fr, base] })
Database Seeding
import { faker } from "@faker-js/faker"
import { PrismaClient } from "@prisma/client"
const prisma = new PrismaClient()
async function seedDatabase() {
faker.seed(42) // Deterministic seed for consistent dev data
// Create users:
const users = await Promise.all(
Array.from({ length: 20 }, () =>
prisma.user.create({
data: {
id: faker.string.uuid(),
email: faker.internet.email(),
name: faker.person.fullName(),
createdAt: faker.date.past({ years: 2 }),
},
})
)
)
// Create packages:
const packageNames = ["react", "vue", "angular", "svelte", "solid-js"]
await Promise.all(
packageNames.map((name) =>
prisma.package.create({
data: {
name,
description: faker.lorem.sentences(2),
weeklyDownloads: faker.number.int({ min: 100000, max: 25000000 }),
version: faker.system.semver(),
},
})
)
)
}
Chance.js
Chance.js is focused on probability distributions — useful when you need weighted random data or specific statistical properties.
import Chance from "chance"
const chance = new Chance()
const seededChance = new Chance(42) // Reproducible with seed
// Person:
const name = chance.name() // "John Smith"
const email = chance.email() // "abc@example.com"
const phone = chance.phone() // "(555) 555-1234"
const age = chance.age({ type: "adult" }) // 25-65
// Addresses:
const city = chance.city()
const country = chance.country({ full: true })
const zip = chance.zip()
// Booleans with probability:
const isActive = chance.bool({ likelihood: 80 }) // 80% chance true
const hasPro = chance.bool({ likelihood: 20 }) // 20% chance true
// Weighted picks:
const tier = chance.weighted(
["free", "pro", "enterprise"],
[70, 25, 5] // 70% free, 25% pro, 5% enterprise
)
// Strings:
const randomString = chance.string({ length: 8, pool: "abcdefghijklmnopqrstuvwxyz" })
const hash = chance.hash({ length: 32 })
// Custom distributions:
const downloads = chance.normal({ mean: 10000, dev: 5000 }) // Normal distribution
const exponential = chance.exp({ rate: 0.001 }) // Exponential distribution
Chance.js custom definitions:
// Extend with custom generators:
Chance.prototype.npmPackage = function() {
const names = ["react", "vue", "angular", "lodash", "express", "axios"]
return this.pickone(names)
}
const chance = new Chance()
const pkg = (chance as any).npmPackage() // Returns a random package name
casual
casual is the simplest option — no configuration, immediate use:
import casual from "casual"
// No instantiation needed:
console.log(casual.name) // "John Smith"
console.log(casual.email) // "john@example.com"
console.log(casual.url) // "http://example.com"
console.log(casual.title) // "Chief Executive Officer"
console.log(casual.description) // Short text
// Re-access generates new data:
console.log(casual.name) // "Jane Doe" (different each time)
// Seed:
casual.seed(42)
console.log(casual.name) // Same each time with this seed
casual has no TypeScript types — use @types/casual or cast with as any.
Feature Comparison
| Feature | @faker-js/faker | Chance.js | casual |
|---|---|---|---|
| TypeScript | ✅ Native | ✅ @types | ❌ |
| Weekly downloads | ~5.8M | ~1.8M | ~250K |
| Locales | 60+ | 10+ | Limited |
| Seeded random | ✅ | ✅ | ✅ |
| Probability/weights | ⚠️ Limited | ✅ Excellent | ❌ |
| Normal distribution | ❌ | ✅ | ❌ |
| Custom generators | ✅ | ✅ | ✅ |
| Faker modules | 50+ categories | General | General |
| Bundle size | ~4MB (full) | ~170KB | ~30KB |
| Tree-shakable | ✅ | ❌ | ❌ |
| Active development | ✅ | ✅ | ⚠️ Slow |
When to Use Each
Choose @faker-js/faker if:
- Generating test fixtures, Prisma seeds, or Storybook mock data
- You need locale-specific data (German addresses, Japanese names, etc.)
- TypeScript is required
- You want a comprehensive library covering persons, commerce, internet, systems
Choose Chance.js if:
- You need weighted/probability distributions (e.g., 80% of users are free tier)
- Generating statistically realistic data distributions
- Simulating real-world skewed data (most users have few downloads; few have millions)
Choose casual if:
- Quick scripts where simplicity beats features
- You're prototyping and don't need TypeScript
- Bundle size matters and you only need basic data types
Methodology
Download data from npm registry (weekly average, February 2026). Feature comparison based on @faker-js/faker v9.x, Chance.js v1.x, and casual v0.6.x.