oxlint + Prettier Migration
What We Did
Section titled “What We Did”Migrated the codebase from Biome (all-in-one linter/formatter) to a split setup:
- oxlint - Fast linter from the oxc project
- Prettier - Industry-standard code formatter
Why This Approach
Section titled “Why This Approach”Biome’s formatter was causing issues with unwanted code transformations (adding semicolons despite configuration, changing indentation). Rather than fight the tool, we switched to a more predictable setup.
Key reasons:
- oxlint is extremely fast and focused purely on linting
- Prettier is battle-tested and respects configuration reliably
- Separating concerns (linting vs formatting) provides better control
- Both tools are well-maintained with active communities
Alternatives considered:
- Keep Biome: Configuration issues were causing developer friction
- ESLint + Prettier: Slower than oxlint, more configuration overhead
Commands Used
Section titled “Commands Used”# Remove Biome, add oxlint and Prettierbun remove @biomejs/biomebun add -d oxlint prettier
# Rename config packagemv packages/biome-config packages/oxlint-configImplementation Details
Section titled “Implementation Details”Package Structure
Section titled “Package Structure”Created @repo/oxlint-config with layered configurations:
packages/oxlint-config/├── package.json├── base.json # Core rules for all packages├── react.json # React-specific rules (extends base)└── next.json # Next.js rules (extends react)oxlint Configuration
Section titled “oxlint Configuration”Base config (packages/oxlint-config/base.json):
{ "$schema": "./node_modules/oxlint/configuration_schema.json", "categories": { "correctness": "error", "suspicious": "warn", "perf": "warn" }, "rules": { "no-unused-vars": "warn", "no-console": "off", "eqeqeq": "error", "no-var": "error", "prefer-const": "warn" }, "env": { "browser": true, "node": true, "es2024": true }, "overrides": [ { "files": ["**/*.test.ts", "**/*.test.tsx", "**/tests/**"], "rules": { "no-constant-binary-expression": "off" } } ]}React config (packages/oxlint-config/react.json):
{ "extends": ["./base.json"], "plugins": ["react", "react-hooks", "jsx-a11y"], "rules": { "react/jsx-key": "error", "react/react-in-jsx-scope": "off", "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn" }}Prettier Configuration
Section titled “Prettier Configuration”Root config (.prettierrc):
{ "useTabs": true, "semi": false, "singleQuote": false, "trailingComma": "es5", "printWidth": 100}Ignore file (.prettierignore):
node_modulesdist.next.astro.turbobun.lockcoverage**/convex/_generatedVS Code Integration
Section titled “VS Code Integration”Added .vscode/settings.json for consistent editor experience:
{ "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, "editor.insertSpaces": false, "typescript.tsdk": "node_modules/typescript/lib"}Recommended extensions in .vscode/extensions.json:
esbenp.prettier-vscode- Prettier formatteroxc.oxc-vscode- oxlint integrationbradlc.vscode-tailwindcss- Tailwind IntelliSenseastro-build.astro-vscode- Astro support
Package Updates
Section titled “Package Updates”Each package references the appropriate config via .oxlintrc.json:
Web app (apps/web/.oxlintrc.json):
{ "extends": ["../../packages/oxlint-config/next.json"]}UI package (packages/ui/.oxlintrc.json):
{ "extends": ["../oxlint-config/react.json"]}Updated lint scripts in each package.json:
{ "scripts": { "lint": "oxlint ." }}Key Dependencies
Section titled “Key Dependencies”oxlint: ^1.42.0 - Fast Rust-based linterprettier: ^3.8.1 - Code formatter
Integration with Existing Code
Section titled “Integration with Existing Code”The migration was seamless:
- Removed all
biome.jsonfiles - Added
.oxlintrc.jsonfiles referencing shared configs - Updated lint scripts from
biome check --writetooxlint . - Added format scripts using Prettier
Context for AI
Section titled “Context for AI”When working with linting and formatting:
- Linting: Run
bun lint(uses oxlint via Turborepo) - Formatting: Run
bun format(uses Prettier) - Config location:
packages/oxlint-config/for lint rules - Style: Tabs, no semicolons, double quotes
- oxlint doesn’t auto-fix - it only reports issues
- Prettier handles all formatting concerns
Outcomes
Section titled “Outcomes”Before
Section titled “Before”- Single tool (Biome) for linting and formatting
- Configuration issues causing unwanted code changes
- Semicolons being added despite
asNeededsetting
- oxlint for fast, reliable linting
- Prettier for predictable formatting
- Clear separation of concerns
- VS Code integration with format-on-save
Testing/Verification
Section titled “Testing/Verification”# Run lintingbun lint
# Check formattingbun format:check
# Apply formattingbun formatExpected results:
bun lintpasses with no errorsbun format:checkpasses after runningbun format- Code uses tabs and no semicolons
Related Documentation
Section titled “Related Documentation”- oxlint Documentation
- Prettier Documentation
- Biome Migration Guide (previous setup)