Skip to main content
v9Scoped packages, git-cliff releases, and new runtime presets

Configuration clarity for serious TypeScript teams

Stop copying configs.Ship a preset.↳ your opinions, versioned

Describe your toolchain once in presetter.config.ts. Presetter installs declared packages and scripts, then generates the ESLint, Vitest and TypeScript config each repo expects, and keeps every repo in step when the preset moves.

$ npx presetter use @presetter/preset-esm

One source of truth for every package

presetter.config.tsshared baseline
import { preset } from 'presetter';import essentials from '@presetter/preset-essentials';import react from '@presetter/preset-react';import strict from '@presetter/preset-strict'; export default preset('app', { extends: [essentials, react, strict],});

The problem

Still copying configs between projects?

Every repo starts clean. Then the same eslint, vitest, typescript, build, and lifecycle settings fork in small ways across apps, packages, services, and CLIs.

Five copies of shared intent, each drifting a little.
workspace/
apps/web/eslint.config.tsReact-specific edits
apps/api/eslint.config.tsSimilar, but not quite the same
packages/ui/vitest.config.tsLocal test tweaks
packages/core/tsconfig.jsonShared intent copied by hand
packages/runtime/package.jsonScripts slowly drift

90-second explainer

Follow one config from start to finish.

Compose presets in one small file, generate the configs your tools expect, override a value in plain sight, and update by bumping the preset and running bootstrap again.

Opinionated by design

The official presets are opinionated. On purpose.

They encode how I build TypeScript projects: ESM first, strict linting, full coverage gates, Husky hooks. That fits my work. It may not fit yours, and Presetter is built for that.

  • preset-essentialsTypeScript, ESLint, Vitest, Prettier and Husky, all switched on.Foundation
  • preset-esmESM-first. Modern Node.js projects and libraries.Module system
  • preset-strictSecurity rules and a 100% coverage gate.Quality
  • preset-webBrowser globals and Tailwind linting.Extension
  • preset-reactReact and TSX tooling.Extension
  • preset-nextesm + node + strict + web + react, composed for the App Router.Framework

Agree, adjust, or replace them.

Three ways to start. All of them are a single file.
A

Use as-is

My defaults suit you. One line and you are done.

// presetter.config.tsexport { default } from '@presetter/preset-esm';
B

Override what differs

Keep the baseline, change the few values you disagree with, in plain sight.

export default preset('my-project', { extends: [esm], override: { variables: { source: 'source' }, assets: { '.gitignore': null }, },});
CMake it yours

Write your own preset

Encode your team’s opinions once and share them across every repo you own.

export default preset('@acme/preset', { extends: [esm], scripts: { test: 'vitest' },});
See how easy it is

Managed scripts

Your package.json scripts come from the preset too.

Each script becomes a one-liner that calls run. Presetter looks the task up in your preset stack, expands the tasks it calls, and forwards anything after --. Update the preset and every repo picks up the new build, test, and release steps.

package.jsonscripts
"scripts": {
}
Need something different? Write it locally.
$ npm run build11 tasks resolved
  1. buildpreset-essentialsrun-s clean build:artifact build:typescript
  2. cleanpreset-essentialsrun-s clean:**
  3. clean:libpreset-essentialszx --eval "fs.remove('{output}')"
  4. clean:coveragepreset-essentialszx --eval "fs.remove('coverage')"
  5. clean:tscpreset-essentialszx --eval "fs.remove('tsconfig.build.tsbuildinfo')"
  6. build:artifactpreset-essentialsrun-s build:artifact:*
  7. build:artifact:packagepreset-essentialszx --eval "fs.ensureDir('{output}')"
  8. build:typescriptpreset-esmrun-s build:typescript:tsc build:typescript:alias build:typescript:mjs:fix
  9. build:typescript:tscpreset-essentialstsc -p tsconfig.build.json
  10. build:typescript:aliaspreset-essentialsrun-s build:typescript:alias:*
  11. build:typescript:mjs:fixpreset-esmtsc-esm-fix --sourceMap --target {output}

preset-esm replaces build:typescript from preset-essentials. Every other step is inherited as-is.

Local wins

A script you write in package.json beats the preset version of the same name. Add --template to run the preset one anyway.

run "test:*"

Patterns select tasks: * matches one level of subtasks, ** matches any depth.

Preset binaries

Each preset adds its bin path to PATH, so eslint or vitest resolve without being direct dependencies.

04Your own managed preset

Creating a preset is easy. It's one TypeScript file.

A preset is the same preset() call you already write in presetter.config.ts, published as a package. Extend an official preset or start from nothing, add your opinions, and every repo that extends it stays in step.

Read the custom preset tutorial
src/index.ts14 lines
import { preset } from 'presetter';import esm from '@presetter/preset-esm'; // your team's opinions, versioned in one placeexport default preset('@acme/preset', { extends: [esm], variables: { source: 'src', output: 'dist' }, setup: { scripts: { build: 'run build', test: 'run test --' } }, assets: { 'tsconfig.json': { compilerOptions: { target: 'ES2024' }, }, },});
extends
Start from official presets, or none at all.
variables
Directories and targets your templates read.
setup
Packages and script delegates added by use.
assets
The config files Presetter generates.

Interactive explorer

Assemble the preset stack that matches your project.

Pick a stack, then run the command in a project with a package.json. use installs its packages and scripts, writes the config, and bootstraps your tools. Your project’s package manager is detected; if none is found, you’ll be asked to choose.

Foundation

Module systems

Runtimes

Extensions

Frameworks

terminal
$ npx presetter use @presetter/preset-esm @presetter/preset-strict
presetter.config.ts
import preset0 from '@presetter/preset-esm';import preset1 from '@presetter/preset-strict'; import { preset } from 'presetter'; import { name } from './package.json' with { type: 'json' }; export default preset(name, { extends: [preset0, preset1],});
Turn this stack into your own preset