npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mockdrop

v1.1.4

Published

Generate high-quality dummy data instantly. Zero dependencies. Works everywhere.

Readme

Mockdrop

Generate high-quality dummy data instantly. Zero dependencies. Works everywhere.

A zero-dependency, isomorphic dummy data generator with a schema-based API, deep customization, and a pluggable architecture built for scale. 13 namespaces covering people, locations, finance, dates, airlines, animals, colors, phones, and more.


Installation

npm install mockdrop

or

yarn add mockdrop

or

pnpm add mockdrop

Quick Start

import mockdrop from "mockdrop";

// Generate an array of 20 lead objects
const leads = mockdrop.create({
  leadName: mockdrop.projectName,
  leadDescription: mockdrop.projectDescription,
  leadAmount: () => mockdrop.amount(1000, 50000),
  leadCreatedAt: mockdrop.pastDate,
  leadCreatedBy: mockdrop.user.name,
  leadSource: mockdrop.platformName,
  leadEmail: () => mockdrop.email({ domain: 'mailinator.com' })
}, 20);

console.log(leads);

Schema value rules

Each value in a create() schema can be:

| Value | Behavior | | --- | --- | | A generator reference — mockdrop.projectName (no parentheses) | Called once per item with its own defaults, so every row gets a fresh value | | Your own arrow function — () => mockdrop.email({ domain: 'mailinator.com' }) | Same, but lets you pass options | | Your own function using the index — (i) => i + 1 | Receives the item index (auto-increment ids) | | A nested plain object | Resolved recursively as a sub-schema | | Anything else — 'admin', 42, true, a Date, an array | Copied as-is into every item |

⚠️ Don't call the generator inside the schema (leadName: mockdrop.projectName()) — that runs once and repeats the same value in all rows. Pass the reference or wrap it in an arrow function.

The item index is handed only to your own functions. Built-in generators always run with their own defaults, so createdAt: mockdrop.pastDate is never quietly invoked as pastDate(0). If you want the index alongside a generator, wrap it yourself:

mockdrop.create({
  id: (i) => i + 1,                              // 1, 2, 3, …
  createdAt: mockdrop.pastDate,                  // default 1-year window
  label: (i) => `${mockdrop.projectName()}-${i}` // both
}, 3);

Ready-made records

When you just need rows on screen, skip the schema entirely:

mockdrop.entity.user(10);
mockdrop.entity.lead(10);
mockdrop.entity.product(10);
mockdrop.entity.order(10);
mockdrop.entity.transaction(10);
mockdrop.entity.blogPost(10);
mockdrop.entity.comment(10);
mockdrop.entity.todo(10);
mockdrop.entity.event(10);

Each preset builds a row as a unit, so fields that ought to agree do — an order's total is the sum of its own subtotal + tax + shipping, an event's endsAt follows its startsAt, and a post's slug comes from its title.

Every preset takes an optional override schema, which accepts anything create() accepts:

mockdrop.entity.user(10, {
  isActive: true,                       // static, on every row
  seq: (i) => i + 1,                    // per row, with the index
  teamId: mockdrop.ref(teams, 'id'),    // a relation (see below)
});

Coherent identities

Generating a name and an email separately gives you two unrelated people in the same object:

mockdrop.create({ name: mockdrop.user.name, email: mockdrop.email }, 1);
// → [{ name: 'Jayesh Goswami', email: '[email protected]' }]  ← reads as fake

person.coherent() builds them from the same person instead:

mockdrop.create({ user: mockdrop.person.coherent }, 1);
// → [{ user: {
//        firstName: 'Jayesh', lastName: 'Goswami', fullName: 'Jayesh Goswami',
//        initials: 'JG',
//        email: '[email protected]',
//        username: 'jayesh_goswami42',
//     } }]

Pin any part of it — the rest is generated to match:

mockdrop.person.coherent({ domain: 'mailinator.com' });

Relations

Real data has relationships: twenty leads belong to five reps, not twenty different people. Generate the parent records first, then reference them.

const reps = mockdrop.create({ id: mockdrop.uuid, name: mockdrop.user.name }, 5);

const leads = mockdrop.create({
  id:      mockdrop.uuid,
  title:   mockdrop.projectName,
  ownerId: mockdrop.ref(reps, 'id'),   // just the id
  owner:   mockdrop.ref(reps),         // or embed the whole record
}, 20);

| Helper | Relation | Behavior | | --- | --- | --- | | ref(list, key?) | many-to-one | Random pick; records repeat | | refUnique(list, key?) | one-to-one | Never repeats; throws once exhausted | | refEach(list, key?) | even split | Cycles in order, so everyone gets a fair share |

Pass a key to store just that field, or omit it to embed the whole record. refUnique and refEach restart on each create() call, so reusing the same schema object is safe.


Paginated responses

Mock an endpoint, not just an array:

mockdrop.paginate({ id: mockdrop.uuid, title: mockdrop.projectName }, {
  page: 2, perPage: 20, total: 137,
});
// → {
//     data: [ …20 records… ],
//     meta: { page: 2, perPage: 20, total: 137, totalPages: 7,
//             hasNextPage: true, hasPrevPage: true },
//   }

The last page is short when total isn't a multiple of perPage, and a page past the end comes back empty — the same way a real endpoint behaves.


TypeScript

The record type is inferred from your schema, so nothing needs annotating:

const leads = mockdrop.create({
  name:      mockdrop.fullName,
  amount:    mockdrop.amountRaw,
  createdAt: mockdrop.pastDate,
  owner:     mockdrop.ref(reps, 'id'),
}, 20);

// leads: { name: string; amount: number; createdAt: Date; owner: string }[]

leads[0].amount.toFixed(2);  // ✅ typed as number
leads[0].nmae;               // ❌ compile error

An explicit type argument still works and takes precedence:

const typed = mockdrop.create<Lead>({ /* … */ }, 20);  // → Lead[]

Customizing Email Domains

Want all emails to come from a specific domain for testing?

const user = mockdrop.create({
  name: () => mockdrop.fullName(),
  email: () => mockdrop.email({ domain: 'mailinator.com' })
});

console.log(user[0].email); // e.g. "[email protected]"

Reproducible Data (Seeding)

Mockdrop uses a seedable PRNG so you can generate the exact same data every time, useful for snapshot testing:

mockdrop.setSeed(42);
console.log(mockdrop.fullName()); // Always returns the same name for seed 42

API Reference

Mockdrop provides an extensive set of generators organized into 13 namespaces. You can reach them via their namespace (mockdrop.person.fullName()) or via top-level shortcuts (mockdrop.fullName()).

Namespace vs. shortcut naming

Three method names are also namespace names. In those cases the namespace wins the top-level slot, and the method stays available in full form:

| You want | Use this | Not this | | --- | --- | --- | | A phone number | mockdrop.phone.number() or mockdrop.person.phone() | ~~mockdrop.phone()~~ — that's the namespace | | A hex color | mockdrop.internet.color() | ~~mockdrop.color()~~ — that's the namespace | | An airline name | mockdrop.airline.airline() | ~~mockdrop.airline()~~ — that's the namespace |

Two more names are claimed by whichever namespace registers first; both forms always work fully qualified:

  • mockdrop.rgb()internet.rgb(). For the richer version use mockdrop.color.rgb({ includeAlpha: true }).
  • mockdrop.timeZone()date.timeZone(). Identical data is at mockdrop.location.timeZone().

Person (mockdrop.person)

firstName() · lastName() · fullName() · age(min, max) · gender() · avatar() · bio() · phone(format) · jobTitle() · prefix() · coherent(options)

mockdrop.user is an alias for mockdrop.person, with user.name() mapping to fullName() — so schemas can read naturally: createdBy: mockdrop.user.name.

Entity (mockdrop.entity)

user(count, overrides) · lead(…) · product(…) · order(…) · transaction(…) · blogPost(…) · comment(…) · todo(…) · event(…)

Relations & responses (top level)

ref(list, key) · refUnique(list, key) · refEach(list, key) · paginate(schema, options)

Internet (mockdrop.internet)

email(options) · exampleEmail(options) · username(options) · displayName() · password(length, options) · url() · ip() · ipv4() · ipv6() · userAgent() · color() · hexColor() · rgb() · mac() · domainName() · domainSuffix() · domainWord() · emoji(options) · httpMethod() · statusCode() · httpStatusCode(options) · protocol() · port() · jwt(options) · jwtAlgorithm()

mockdrop.internet.exampleEmail();                          // "[email protected]" (RFC 2606 safe)
mockdrop.internet.emoji({ types: ['animals'] });           // "🐻"
mockdrop.internet.httpStatusCode({ types: ['serverError'] }); // 503
mockdrop.internet.jwt();                                   // "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.…"

jwt() is structurally valid (header.payload.signature, base64url-encoded) but the signature is random — it's for shaping mock data, not for auth testing.

Location (mockdrop.location)

buildingNumber() · cardinalDirection() · ordinalDirection() · direction() · city() · continent() · country() · countryCode() · county() · language() · state() · street() · streetAddress(useFullAddress) · secondaryAddress() · postalAddress() · zipCode(format) · latitude(min, max, precision) · longitude(min, max, precision) · nearbyGPSCoordinate(options) · timeZone()

mockdrop.location.postalAddress();          // "3402 Birch Court, Dublin, Alaska 16942"
mockdrop.location.zipCode('#####-####');    // "48201-9317"
mockdrop.location.nearbyGPSCoordinate({ origin: [40.7128, -74.006], radius: 5 }); // [40.7194, -73.9498]

Each key resolves independently, so country() and countryCode() in the same schema won't match each other. Pick one, or derive both from a single () => { … } function.

Company (mockdrop.company)

name() · catchPhrase() · industry() · platformName() · projectName() · projectDescription() · department() · buzzword()

Date (mockdrop.date)

past(years) / pastDate(years) · future(years) / futureDate(years) · recent(days) · soon(days) · anytime() · between(from, to) · betweens(from, to, count) · birthdate(options) · month(options) · weekday(options) · timeZone() · timestamp() · iso() · time() · year(min, max)

mockdrop.date.birthdate({ min: 25, max: 40 });              // age-based (default)
mockdrop.date.birthdate({ min: 1990, max: 2000, mode: 'year' });
mockdrop.date.betweens(new Date('2024-01-01'), new Date('2025-01-01'), 5); // 5 sorted dates
mockdrop.date.month({ abbreviated: true });                 // "Feb"

Finance (mockdrop.finance)

amount(min, max, decimals) · amountRaw(…) · currency() · currencyCode() · currencyName() · currencyNumericCode() · currencySymbol() · accountName() · accountNumber(length) · routingNumber() · bic() · creditCard() · creditCardFull() · creditCardNumber(issuer) · creditCardIssuer() · creditCardCVV() · pin() · transactionId() · transactionType() · transactionDescription() · bitcoinAddress() · litecoinAddress() · ethereumAddress() · iban()

mockdrop.finance.creditCardNumber('visa');  // "4532 8821 0049 7211" — passes Luhn validation
mockdrop.finance.bic();                     // "ZPLGSG5N"
mockdrop.finance.ethereumAddress();         // "0xd15f12f241295fc6f78ada43255060e7508826a7"

creditCardNumber() produces Luhn-valid, correctly-prefixed numbers so they survive form validation. They're structurally valid only — never tied to a real account.

Airline (mockdrop.airline)

aircraftType() · airline() · airplane() · airport() · flightNumber(options) · recordLocator(options) · seat()

mockdrop.airline.flightNumber();                   // "BA353"
mockdrop.airline.airport();                        // { name: "…", iataCode: "IST", city: "Istanbul" }
mockdrop.airline.recordLocator();                  // "5YX1H9"
mockdrop.airline.seat();                           // "39C"

Animal (mockdrop.animal)

bear() · bird() · cat() · cetacean() · cow() · crocodilia() · dog() · fish() · horse() · insect() · lion() · petName() · rabbit() · rodent() · snake() · type()

Color (mockdrop.color)

rgb(options) · cmyk() · hsl(options) · hwb() · lab() · lch() · human() · space() · cssSupportedFunction() · cssSupportedSpace() · colorByCSSColorSpace(options)

mockdrop.color.human();                          // "Cerulean"
mockdrop.color.rgb({ format: 'array' });         // [122, 30, 200]
mockdrop.color.rgb({ includeAlpha: true });      // "rgba(122, 30, 200, 0.42)"
mockdrop.color.colorByCSSColorSpace({ space: 'display-p3' });

Phone (mockdrop.phone)

number(format) · imei()

mockdrop.phone.number('IN');   // "+91 17931 04838"  (also 'US', 'UK', 'INTERNATIONAL')
mockdrop.phone.imei();         // "19-348283-094016-6" — Luhn-valid

Lorem (mockdrop.lorem)

word() · words(count) · sentence(wordCount) · sentences(count) · paragraph(sentenceCount) · paragraphs(count) · slug(wordCount) · lines(count) · text(length)

System (mockdrop.system)

uuid() · objectId() · fileName(ext) · fileExt() · mimeType() · semver() · filePath() · directoryPath() · commonFileType()

Helpers (mockdrop.helpers)

pick(array) · pickMultiple(array, count) · pickUnique(array, count) · shuffle(array) · unique(fn, count) · maybe(fn, probability) · replicate(fn, count) · int(min, max) · float(min, max, decimals) · bool(probability) · letter() · alphaNumeric(length) · arrayElement(array) · objectValue(obj) · objectKey(obj) · enumValue(enumObj)


Architecture

  • Isomorphic: Works in Node.js and the Browser
  • Zero dependencies: Ships nothing but its own code
  • TypeScript: Written with JSDoc and full .d.ts types for rich IntelliSense
  • Pluggable: Easy to extend with custom namespaces and data

Every generator draws from one seedable PRNG, so setSeed() makes an entire dataset — across every namespace — reproducible.

Adding a namespace follows one pattern: drop the word lists in src/data/, add a createXGenerator(prng) factory in src/generators/, register it in src/core/engine.js, then extend src/types/index.d.ts.


License

MIT © Jayesh Puri Goswami