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

@tailor-platform/sdk-plugin-seed

v0.3.6

Published

Tailor CLI plugin providing the `tailor seed` commands (TailorDB and IdP seed data)

Readme

@tailor-platform/sdk-plugin-seed

Tailor CLI plugin that provides the tailor seed commands: seed TailorDB (and IdP _User) data from JSONL files generated by seedPlugin, dump the rows currently in TailorDB back out as seed data, validate that data against the generated schemas, and fill in the create-time values the data needs, such as the ids that express relations.

[!NOTE] This package is a CLI plugin: it ships an external tailor-seed executable that the Tailor CLI dispatches to when you run tailor seed. Keep seedPlugin from @tailor-platform/sdk/plugin/seed in definePlugins() — it generates the seed data and schema files this plugin consumes.

Installation

Install it next to @tailor-platform/sdk in your project:

npm install -D @tailor-platform/sdk-plugin-seed@next

The Tailor CLI discovers the plugin automatically from node_modules/.bin (or your PATH). Run tailor plugin list to confirm it resolves.

Usage

# Seed everything (TailorDB tables, then IdP _User)
tailor seed apply

# Truncate target tables first, without a confirmation prompt
tailor seed apply --truncate --yes

# Seed a single TailorDB namespace (excludes _User)
tailor seed apply --namespace my-db

# Seed specific tables only
tailor seed apply User Order

# Validate JSONL seed data against the generated schemas
tailor seed validate
tailor seed validate ./seed/data/User.jsonl

# Fill in the ids rows are missing (and any other create-time field)
tailor seed fill
tailor seed fill --fields id,createdAt
tailor seed fill ./seed/data/User.jsonl

# Fill, then check the result
tailor seed fill && tailor seed validate

# Update existing rows (matched by id, or by name for _User) instead of failing on duplicates
tailor seed apply --upsert

# Write the rows currently in TailorDB out as JSONL seed data
tailor seed dump --out ./snapshot
tailor seed dump --namespace my-db --out ./snapshot
tailor seed dump --force User Order

Validating seed data

tailor seed validate checks every row against the table it seeds: field types, required fields, the table's own validate, and the relations between files. A row is also rejected when it carries a field the table does not declare, at the top level or inside a nested object:

seed/data/Company.jsonl:3 • legacyCode: Field "legacyCode" is not declared by the table. Remove it from the row, or add it to the table definition and run `tailor generate`.

This is what catches seed data that has drifted from the table definition — a column that still exists in a deployed environment but was removed from tailor.config.ts, or a typo in a field name — before tailor seed apply turns it into a database error. The check follows the generated schema files, so run tailor generate after changing a table or attaching a plugin to one. Fields a plugin adds to the table are validated like the table's own. IdP _User rows are not checked this way, since their extra keys are user attributes.

Dumping the current data back out

tailor seed dump reads the rows a deployed app currently holds and writes them as JSONL, one file per table, in the format tailor seed apply reads. That makes a dump the restore point for the change you are about to make:

tailor seed dump --force
# ... run the migration, the executor, the workflow you want to try ...
tailor seed apply --truncate --yes --skip-idp

Naming tables limits the dump to them, and --namespace limits it to one namespace, so a table you are about to change can be captured and put back on its own rather than resetting the whole app.

Restoring needs --skip-idp unless you also have a separate backup of _User. A dump never captures _User (see below), so tailor seed apply --truncate without --skip-idp would truncate the app's current IdP users and reseed _User from whatever _User.jsonl already has on disk — data the dump did not just refresh, and that may no longer match who has actually signed up. Add --skip-idp to the restore unless you have separately backed up and intend to restore _User too.

Fields the platform assigns rather than the seed row — serial fields — are left out, unless another table's relation is keyed to that field, in which case it is kept so the relation still resolves after apply --truncate gives the row a fresh value. Explicit nulls are kept as-is, so a dumped line reads back the way a hand-written one does and tailor seed validate accepts it. Rows are read a page at a time, ordered by id, and written to disk as each page arrives rather than held in memory for the whole table; --page-size changes how many come back per request.

Without --out, the files land in the seed data directory under the seedPlugin distPath, on top of the data that is already there — so a file that already exists is only overwritten with --force:

2 JSONL file(s) already exist in /project/seed/data: User, Order. Pass --force to overwrite them, or --out to write elsewhere.

IdP _User records are never dumped. Their credentials do not survive a round trip through seed JSONL, so naming _User is an error rather than a partial export; keep that data under version control instead.

Two things the dump does not capture: the bytes behind stored file fields, and which rows came from a previous seed rather than from the app — a dump is the whole current state of the tables it covers.

Paging is not safe against concurrent writes. Each page is fetched with id as a keyset cursor, but TailorDB ids are UUIDs rather than a monotonic sequence, so a row inserted after paging starts can land before the cursor already handed out and never be seen. Dumping a table that a running app keeps writing to can therefore miss rows written during the dump; for a true point-in-time restore point, pause writes (or dump from a replica/snapshot) before running tailor seed dump.

The machine user needs unconditional read access. TailorDB read permission conditions filter rows per record, so a machine user that can only see a subset of a table still gets a successful result back — just a smaller one — and the dump reports that subset as the complete table. Restoring from it with apply --truncate then permanently drops the rows the machine user could not see, with no error at any point. Grant the machine user used for tailor seed dump unconditional read access to every table you dump.

Filling in create-time values

A relation in seed data points at a field of the row it references — usually its id — so a row you want to reference needs an id written in the file. tailor seed fill writes the value a record would get on create into the rows that are missing it, id by default:

# ./seed/data/Customer.jsonl before
{"name":"Acme Corporation","email":"[email protected]"}
# after
{"id":"0b6b6f5e-3b8a-4d0e-9a1f-2c7d8e5a4b31","name":"Acme Corporation","email":"[email protected]"}

--fields names what to fill, so any field the table gives a value to on create can be written the same way — --fields id,createdAt also stamps a creation time on rows that have none, which is how you seed records that need to look older than the seed run:

tailor seed fill --fields id,createdAt

The values come from the table itself — its id, its field defaults, its create hooks — applied to each row on its own.

Nothing is validated. That is deliberate: the ids are what you need in order to write the rows that reference them, so waiting for the data to be valid would be waiting for the thing this command gives you. A row can be filled while a required field is still missing, or while another file references an id that does not exist yet. Run tailor seed validate once the data is ready.

Only the named fields are written, and only into a row that has no value for them, so a value already in the file is never replaced — a row that already carries a createdAt keeps it. A field the table gives no value to is skipped: --fields id leaves the IdP _User data alone, whose rows are identified by name, and a field the platform assigns rather than the table — a serial field — has nothing to fill in from here:

⚠ No seed data produces a value for: invoiceNumber
✓ Nothing to fill

A line that gains nothing is left exactly as it was, byte for byte. Only the lines that take a value are rewritten, and those get their keys in the order the table declares its fields, so a filled-in id lands at the front of the line and a createdAt next to the other timestamps. Keys the table does not declare follow the declared ones.

The values are read from the schema files seedPlugin generates next to the data. Every one of them is read before anything is written, so a project that has not run tailor generate since upgrading is told which file to regenerate and keeps its data untouched:

./seed/data/Customer.schema.ts does not export `hook`. Run `tailor generate` to regenerate the seed schema files.

Naming a single .jsonl file limits the run to that file, so a referenced table can be filled on its own before the rows that reference it are written.

Without --upsert, a row whose id already exists in a target table fails the seed run. With --upsert, every row must supply an id (and any field the table requires) — run tailor seed fill first if some rows have none — and a matching row is updated in place instead. Because the update goes through the same write path as any other update, it runs update hooks and validation and updates fields such as updatedAt, and it publishes a record-updated event — so an executor using recordUpdatedTrigger fires for each existing row that gets updated.

The machine user used for seeding comes from --machine-user or the machineUserName seedPlugin option:

definePlugins(
  seedPlugin({
    distPath: "./seed",
    machineUserName: "admin-machine-user",
  }),
);

Run tailor seed <command> --help for the full option reference.