Biome Integration Guide
Learn how to use Biome with FieldTest for linting and code quality.
What is Biome?
Biome is a fast, all-in-one toolchain for JavaScript and TypeScript that provides:
- 🚀 Fast linting — Faster than ESLint
- 🎨 Code formatting — Alternative to Prettier
- 🔧 Import sorting — Organize imports automatically
- 🔌 Plugin system — Custom rules via GritQL
FieldTest includes custom Biome plugins to help with migration and enforce best practices.
Quick Start
1. Install Biome
pnpm add -D @biomejs/biome
2. Initialize Biome
pnpm exec biome init
This creates a biome.json
configuration file.
3. Add FieldTest Plugins
Update your biome.json
:
{
"$schema": "https://biomejs.dev/schemas/2.2.5/schema.json",
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"formatter": {
"enabled": true,
"indentStyle": "tab",
"lineWidth": 100
},
"plugins": [
"./grit-plugins/fieldtest-migration.grit",
"./grit-plugins/schema-usage.grit"
]
}
4. Run Biome
# Lint your code
pnpm biome lint
# Format your code
pnpm biome format --write .
# Check and fix issues
pnpm biome check --write .
FieldTest Plugins
Migration Helper Plugin
Detects legacy @fieldtest/*
imports and outdated type names.
What it catches:
// ⚠️ Warning: Legacy import
import { parseMarkdown } from '@fieldtest/core';
// ❌ Error: Outdated type name
const doc: OldDocumentType = parseMarkdown(content);
Suggested fixes:
// ✅ Use unified package
import { parseMarkdown, FieldTestDocument } from '@watthem/fieldtest';
const doc: FieldTestDocument = parseMarkdown(content);
Schema Usage Plugin
Ensures validation results are properly handled.
What it catches:
// ⚠️ Warning: Result not checked
const result = validateWithSchema(content, schema);
console.log('Done'); // Missing result.valid check
// ❌ Error: Missing required fields
const schema = {
name: 'blog-post',
// Missing 'version' field
fields: { /* ... */ }
};
Suggested fixes:
// ✅ Check validation result
const result = validateWithSchema(content, schema);
if (!result.valid) {
console.error('Validation failed:', result.errors);
throw new Error('Invalid content');
}
// ✅ Complete schema
const schema = {
version: '1',
name: 'blog-post',
fields: { /* ... */ }
};
Configuration
Complete biome.json Example
{
"$schema": "https://biomejs.dev/schemas/2.2.5/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": false,
"ignore": [
"node_modules",
"dist",
"build",
".turbo",
"coverage",
"*.config.js"
]
},
"formatter": {
"enabled": true,
"indentStyle": "tab",
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "warn"
},
"correctness": {
"noUnusedVariables": "error"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"semicolons": "always"
}
},
"assist": {
"enabled": true,
"actions": {
"source": {
"organizeImports": "on"
}
}
},
"plugins": [
"./grit-plugins/fieldtest-migration.grit",
"./grit-plugins/schema-usage.grit"
]
}
NPM Scripts
Add Biome commands to package.json
:
{
"scripts": {
"lint": "biome lint .",
"format": "biome format --write .",
"check": "biome check --write .",
"ci:check": "biome check ."
}
}
Editor Integration
VS Code
Install the Biome extension:
code --install-extension biomejs.biome
settings.json:
{
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports.biome": "explicit"
}
}
JetBrains (WebStorm, IntelliJ)
Install the Biome plugin:
- Go to Settings → Plugins
- Search for "Biome"
- Install and restart
Configure in Settings → Languages & Frameworks → Biome.
CI Integration
GitHub Actions
Add Biome checks to your CI pipeline:
.github/workflows/lint.yml:
name: Lint and Format
on: [push, pull_request]
jobs:
biome:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Run Biome
run: pnpm biome check .
Pre-commit Hooks
Use Husky and lint-staged:
package.json:
{
"scripts": {
"prepare": "husky install"
},
"lint-staged": {
"*.{ts,tsx,js,jsx}": [
"biome check --write --no-errors-on-unmatched"
]
}
}
.husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm lint-staged
Migration from ESLint/Prettier
Step 1: Backup Configuration
cp .eslintrc.json .eslintrc.json.backup
cp .prettierrc .prettierrc.backup
Step 2: Migrate Configuration
# Migrate ESLint config
pnpm biome migrate eslint
# Migrate Prettier config
pnpm biome migrate prettier
Biome will read your existing configuration and update biome.json
.
Step 3: Update Scripts
Before:
{
"scripts": {
"lint": "eslint .",
"format": "prettier --write ."
}
}
After:
{
"scripts": {
"lint": "biome lint .",
"format": "biome format --write .",
"check": "biome check --write ."
}
}
Step 4: Remove Old Dependencies
pnpm remove eslint prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin
Step 5: Clean Up Config Files
rm .eslintrc.json .prettierrc .eslintignore .prettierignore
Working with Monorepos
Root Configuration
biome.json (root):
{
"extends": [],
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"plugins": [
"./grit-plugins/fieldtest-migration.grit",
"./grit-plugins/schema-usage.grit"
]
}
Package-Specific Configuration
packages/my-package/biome.json:
{
"extends": ["../../biome.json"],
"linter": {
"rules": {
"suspicious": {
"noConsoleLog": "off"
}
}
}
}
Turbo Integration
Add Biome to your Turbo pipeline:
turbo.json:
{
"pipeline": {
"lint": {
"dependsOn": ["^lint"],
"outputs": []
},
"format": {
"dependsOn": ["^format"],
"outputs": ["**/*.{ts,tsx,js,jsx}"]
}
}
}
Root package.json:
{
"scripts": {
"lint": "turbo run lint",
"format": "turbo run format"
}
}
Advanced Usage
Ignore Specific Diagnostics
Use comments to disable rules:
// biome-ignore lint/suspicious/noExplicitAny: Legacy code
function legacyFunction(data: any) {
// ...
}
Custom Plugins
Create your own GritQL plugins:
grit-plugins/custom-rule.grit:
language js
pattern avoid_console_log() {
`console.log($args)` where {
register_diagnostic(
message = "Avoid console.log in production code. Use a logger instead.",
severity = "warn"
)
}
}
Add to biome.json
:
{
"plugins": [
"./grit-plugins/fieldtest-migration.grit",
"./grit-plugins/schema-usage.grit",
"./grit-plugins/custom-rule.grit"
]
}
Performance Tips
1. Use Glob Patterns
Lint specific directories:
pnpm biome lint src/ packages/
2. Parallel Execution
In monorepos, use Turbo for parallel execution:
pnpm turbo run lint
3. Cache Results
Biome caches results automatically. Use --use-server
for faster subsequent runs:
pnpm biome lint --use-server
Troubleshooting
Issue: Plugins Not Working
Error: Plugin diagnostics not showing
Solution:
- Check plugin paths in
biome.json
- Ensure
.grit
files exist - Run with
--verbose
to see plugin loading
pnpm biome lint --verbose
Issue: Format Conflicts
Error: Biome format differs from Prettier
Solution: Migrate Prettier config:
pnpm biome migrate prettier
Or manually adjust formatting settings in biome.json
.
Issue: Slow Linting
Error: Biome is slower than expected
Solutions:
- Reduce file scope:
pnpm biome lint src/
- Add files to ignore list in
biome.json
- Disable unused plugins
Best Practices
1. Run Biome in CI
Catch issues before merge:
- name: Lint
run: pnpm biome check .
2. Format on Save
Configure your editor to format on save.
3. Use Pre-commit Hooks
Prevent committing unformatted code:
pnpm lint-staged
4. Keep Configuration Simple
Start with recommended
rules, add custom rules as needed.
5. Document Custom Rules
If you create custom plugins, document what they check and why.