Linting and formatting
Status: Scaffolded 2026-09-24
One tool, Biome 2.5.x, does linting, formatting, and import sorting in all four repos. No ESLint, no Prettier, no per-repo drift: biome.json is copied from shared/ and the $schema line is pinned to the installed version so the editor extension and the CLI agree.
The configuration
{
"$schema": "https://biomejs.dev/schemas/2.5.14/schema.json",
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
"files": { "ignoreUnknown": true },
"formatter": { "indentStyle": "space", "indentWidth": 2, "lineWidth": 100, "lineEnding": "lf" },
"linter": {
"rules": {
"recommended": true,
"complexity": { "noExcessiveCognitiveComplexity": { "level": "warn", "options": { "maxAllowedComplexity": 15 } } },
"correctness": { "noUnusedImports": "error", "noUnusedVariables": "error" },
"style": { "useConst": "error" },
"suspicious": { "noConsole": "warn" }
}
},
"javascript": { "formatter": { "quoteStyle": "single", "semicolons": "always", "trailingCommas": "all" } },
"assist": { "actions": { "source": { "organizeImports": "on" } } }
}
Why these settings
- 100 columns. Wide enough for a zod schema or a Mongoose index line without wrapping, narrow enough for two files side by side.
- Single quotes, semicolons, trailing commas. Matches the Express, Expo, and Next ecosystems' defaults, so pasted examples do not get reformatted into noise.
- LF, always. The repos are edited on Windows and built on Linux (CI, EC2, Amplify, EAS). One line ending in git means one diff.
.gitattributes(* text=auto eol=lf) and.editorconfigsay the same thing so the three tools never disagree. - Cognitive complexity 15, warn. A route handler that trips this is usually doing validation, authorization, and the query in one function. The warning is a prompt to move a piece into
services/, not a build failure. - Unused imports and variables are errors. In a privacy-sensitive codebase an unused import is often a leftover from a removed data path. It fails the build so it gets removed rather than accumulated.
noConsolewarns. The API logs through pino; aconsole.login a route is a body waiting to be printed.useIgnoreFile. Biome honors.gitignore, sonode_modules,build,.next, anddistare never scanned.
Commands
npm run lint # biome check .
npm run lint:fix # biome check --write .
lint-staged runs biome check --write on staged files at commit time, see pre-commit hooks.
The CRLF trap on Windows
If git checks a file out with CRLF (a global core.autocrlf=true from before .gitattributes existed, or a file created by a Windows tool), Biome reports a format error on every line of it and validate fails while the code looks fine. Confirm with file <path> in Git Bash; it prints with CRLF line terminators. Fix the file in place:
sed -i 's/\r$//' path/to/file.ts
For a whole checkout after fixing attributes: git add --renormalize . then commit. PowerShell's Out-File also writes a UTF-8 BOM by default, which Biome flags too; write files from Git Bash or with -Encoding ascii when the content allows.