Configure Biome for JavaScript & TypeScript in VS Code

Learn how to configure Biome in VS Code for JavaScript, TypeScript, React, and Next.js projects. Set up biome.json, format on save, linting, import sorting, CI checks, and recommended VS Code extensions.

Dev Kraken Updated 8 min read
Configure Biome for JavaScript & TypeScript in VS Code

When working on modern JavaScript, TypeScript, React, or Next.js projects, consistent formatting and fast linting are essential. A clean setup helps teams avoid style debates, reduce code review noise, and catch common issues before they reach production.

Biome is a fast formatter, linter, and code-assist toolchain for web projects. Instead of managing separate ESLint and Prettier configurations, Biome gives you formatting, linting, import organization, and code fixes from one tool.

In this guide, you will learn how to configure Biome in VS Code using the latest Biome setup, including biome.json, workspace settings, recommended extensions, and CI commands.

Why Use Biome?

Biome is a strong choice for modern JavaScript and TypeScript projects because it is fast, simple, and built around a single configuration file.

Key benefits include:

  • Fast formatting and linting
  • One configuration file
  • Built-in lint rules
  • Import organization
  • VS Code integration
  • CI-friendly commands
  • Support for JavaScript, TypeScript, JSX, TSX, JSON, and CSS

Biome is especially useful when you want a simpler alternative to managing ESLint and Prettier together.

Install Biome

Biome is best installed as a development dependency in your project.

npm

npm i -D -E @biomejs/biome

pnpm

pnpm add -D -E @biomejs/biome

bun

bun add -D -E @biomejs/biome

yarn

yarn add -D -E @biomejs/biome

The -E flag pins the exact Biome version, which helps keep formatting consistent across your team.

Initialize Biome

After installing Biome, generate a configuration file:

npx @biomejs/biome init

For pnpm:

pnpx @biomejs/biome init

For bun:

bunx --bun @biomejs/biome init

For yarn:

yarn exec biome -- init

This creates a biome.json file in your project.

Biome also supports biome.jsonc if you prefer comments in your configuration.

Configure biome.json

Your biome.json file is the main configuration file for Biome.

Below is a practical setup for JavaScript, TypeScript, React, Next.js, JSON, and CSS projects.

{
  "$schema": "https://biomejs.dev/schemas/2.4.13/schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true,
    "defaultBranch": "main"
  },
  "files": {
    "ignoreUnknown": true,
    "includes": [
      "**/*.js",
      "**/*.jsx",
      "**/*.ts",
      "**/*.tsx",
      "**/*.json",
      "**/*.jsonc",
      "**/*.css",
      "**/*.scss"
    ],
    "experimentalScannerIgnores": [
      "**/node_modules/**",
      "**/.next/**",
      "**/dist/**",
      "**/build/**",
      "**/coverage/**",
      "**/.turbo/**",
      "**/out/**",
      "**/.vercel/**",
      "**/storybook-static/**",
      "**/.env*",
      "**/public/**",
      "**/*.d.ts"
    ]
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100,
    "lineEnding": "lf",
    "attributePosition": "auto"
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "style": {
        "noDefaultExport": "off",
        "noImplicitBoolean": "off",
        "noInferrableTypes": "error",
        "noNamespace": "error",
        "noNegationElse": "warn",
        "noNonNullAssertion": "error",
        "noParameterAssign": "error",
        "noUnusedTemplateLiteral": "error",
        "noUselessElse": "warn",
        "useBlockStatements": "error",
        "useCollapsedElseIf": "error",
        "useConst": "error",
        "useDefaultParameterLast": "error",
        "useEnumInitializers": "error",
        "useExportType": "error",
        "useFilenamingConvention": {
          "level": "error",
          "options": {
            "strictCase": false,
            "requireAscii": true,
            "filenameCases": ["kebab-case"]
          }
        },
        "useForOf": "error",
        "useFragmentSyntax": "error",
        "useImportType": "error",
        "useNamingConvention": {
          "level": "error",
          "options": {
            "strictCase": false,
            "conventions": [
              {
                "selector": {
                  "kind": "function"
                },
                "formats": ["camelCase", "PascalCase"]
              },
              {
                "selector": {
                  "kind": "variable"
                },
                "formats": ["camelCase", "PascalCase", "CONSTANT_CASE"]
              },
              {
                "selector": {
                  "kind": "typeLike"
                },
                "formats": ["PascalCase"]
              }
            ]
          }
        },
        "useNodejsImportProtocol": "error",
        "useNumberNamespace": "error",
        "useSelfClosingElements": "error",
        "useShorthandAssign": "error",
        "useShorthandFunctionType": "error",
        "useSingleVarDeclarator": "error",
        "useTemplate": "error",
        "useThrowOnlyError": "error"
      },
      "suspicious": {
        "noExplicitAny": "error",
        "noDebugger": "error",
        "noDuplicateJsxProps": "error",
        "noDuplicateObjectKeys": "error",
        "noDuplicateParameters": "error",
        "noShadowRestrictedNames": "error",
        "noSparseArray": "error",
        "noUnsafeNegation": "error",
        "noArrayIndexKey": "warn",
        "noAssignInExpressions": "error",
        "noCatchAssign": "error",
        "noClassAssign": "error",
        "noCommentText": "error",
        "noCompareNegZero": "error",
        "noConsole": "warn",
        "noConstEnum": "error",
        "noControlCharactersInRegex": "error",
        "noDoubleEquals": "error",
        "noDuplicateCase": "error",
        "noEmptyBlockStatements": "error",
        "noFallthroughSwitchClause": "error",
        "noFunctionAssign": "error",
        "noGlobalAssign": "error",
        "noLabelVar": "error",
        "noMisleadingCharacterClass": "error",
        "noPrototypeBuiltins": "error",
        "noRedeclare": "error",
        "noSelfCompare": "error",
        "noUnknownAtRules": "off"
      },
      "correctness": {
        "noConstAssign": "error",
        "noConstructorReturn": "error",
        "noEmptyPattern": "error",
        "noInvalidConstructorSuper": "error",
        "noInvalidUseBeforeDeclaration": "error",
        "noSelfAssign": "error",
        "noSetterReturn": "error",
        "noSwitchDeclarations": "error",
        "noUnreachable": "error",
        "noUnreachableSuper": "error",
        "noUnsafeFinally": "error",
        "noUnsafeOptionalChaining": "error",
        "noUnusedLabels": "error",
        "noUnusedVariables": "error",
        "useExhaustiveDependencies": "error",
        "useHookAtTopLevel": "error",
        "useIsNan": "error",
        "useJsxKeyInIterable": "error",
        "useValidForDirection": "error",
        "useYield": "error"
      },
      "complexity": {
        "noBannedTypes": "error",
        "noExcessiveCognitiveComplexity": {
          "level": "warn",
          "options": {
            "maxAllowedComplexity": 15
          }
        },
        "noForEach": "warn",
        "noStaticOnlyClass": "error",
        "noThisInStatic": "error",
        "noUselessCatch": "error",
        "noUselessConstructor": "error",
        "noUselessFragments": "error",
        "noUselessLabel": "error",
        "noUselessRename": "error",
        "noUselessSwitchCase": "error",
        "noUselessTernary": "error",
        "noUselessTypeConstraint": "error",
        "noVoid": "error",
        "useFlatMap": "error",
        "useLiteralKeys": "error",
        "useOptionalChain": "error",
        "useSimpleNumberKeys": "error",
        "useSimplifiedLogicExpression": "error"
      },
      "security": {
        "noDangerouslySetInnerHtml": "error",
        "noDangerouslySetInnerHtmlWithChildren": "error",
        "noGlobalEval": "error"
      },
      "a11y": {
        "noAccessKey": "error",
        "noAriaHiddenOnFocusable": "error",
        "noAriaUnsupportedElements": "error",
        "noAutofocus": "error",
        "noDistractingElements": "error",
        "noHeaderScope": "error",
        "noInteractiveElementToNoninteractiveRole": "error",
        "noNoninteractiveElementToInteractiveRole": "error",
        "noNoninteractiveTabindex": "error",
        "noPositiveTabindex": "error",
        "noRedundantAlt": "error",
        "noRedundantRoles": "error",
        "useFocusableInteractive": "error",
        "useIframeTitle": "error",
        "useKeyWithClickEvents": "error",
        "useKeyWithMouseEvents": "error",
        "useMediaCaption": "error",
        "useSemanticElements": "error",
        "useValidAnchor": "error",
        "useValidAriaProps": "error",
        "useValidAriaValues": "error",
        "useValidLang": "error"
      },
      "performance": {
        "noAccumulatingSpread": "warn",
        "noDelete": "error"
      }
    },
    "domains": {
      "next": "all",
      "react": "recommended"
    }
  },
  "assist": {
    "actions": {
      "source": {
        "organizeImports": {
          "level": "off",
          "options": {
            "groups": [
              ":URL:",
              ":BLANK_LINE:",
              [":BUN:", ":NODE:"],
              ":BLANK_LINE:",
              ":PACKAGE_WITH_PROTOCOL:",
              ":BLANK_LINE:",
              [":PACKAGE:", "!@/**", "!#*", "!~*", "!$*", "!%*"],
              ":BLANK_LINE:",
              ["@/**", "#*", "~*", "$*", "%*"],
              ":BLANK_LINE:",
              [":PATH:", "!./**", "!../**"],
              ":BLANK_LINE:",
              ["../**"],
              ":BLANK_LINE:",
              ["./**"]
            ],
            "identifierOrder": "natural"
          }
        },
        "useSortedAttributes": "on"
      }
    }
  },
  "javascript": {
    "formatter": {
      "arrowParentheses": "always",
      "bracketSameLine": false,
      "bracketSpacing": true,
      "jsxQuoteStyle": "double",
      "quoteProperties": "asNeeded",
      "quoteStyle": "double",
      "semicolons": "always",
      "trailingCommas": "es5"
    },
    "globals": ["console", "process", "__dirname", "__filename"]
  },
  "json": {
    "formatter": {
      "trailingCommas": "none",
      "indentStyle": "space",
      "indentWidth": 2
    }
  },
  "css": {
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentWidth": 2,
      "lineWidth": 100,
      "quoteStyle": "double"
    },
    "linter": {
      "enabled": true
    }
  },
  "overrides": [
    {
      "includes": ["**/*.test.{js,ts,tsx}", "**/*.spec.{js,ts,tsx}", "**/__tests__/**"],
      "linter": {
        "rules": {
          "suspicious": {
            "noExplicitAny": "off",
            "noConsole": "off"
          },
          "style": {
            "noNonNullAssertion": "off"
          }
        }
      }
    },
    {
      "includes": ["**/next.config.{js,ts}", "**/tailwind.config.{js,ts}", "**/*.config.{js,ts}"],
      "linter": {
        "rules": {
          "style": {
            "noDefaultExport": "off"
          },
          "suspicious": {
            "noExplicitAny": "off"
          }
        }
      }
    },
    {
      "includes": ["**/pages/**", "**/app/**/page.{tsx,jsx}", "**/app/**/layout.{tsx,jsx}"],
      "linter": {
        "rules": {
          "style": {
            "noDefaultExport": "off"
          }
        }
      }
    },
    {
      "includes": ["**/*.d.ts", "**/lib/env/*.ts"],
      "linter": {
        "rules": {
          "style": {
            "noNamespace": "off",
            "useNamingConvention": {
              "level": "error",
              "options": {
                "strictCase": false,
                "conventions": [
                  {
                    "selector": {
                      "kind": "objectLiteralProperty"
                    },
                    "formats": ["CONSTANT_CASE", "camelCase"]
                  }
                ]
              }
            }
          },
          "suspicious": {
            "noExplicitAny": "error"
          },
          "complexity": {
            "noExcessiveCognitiveComplexity": {
              "level": "error",
              "options": {
                "maxAllowedComplexity": 12
              }
            }
          }
        }
      }
    }
  ]
}

This configuration enables formatting, linting, assist actions, React rules, Next.js rules, accessibility checks, performance checks, and project-specific overrides.

Configure VS Code for Biome

Install the official Biome VS Code extension:

{
  "recommendations": ["biomejs.biome"]
}

Then add this to .vscode/settings.json:

{
  "editor.defaultFormatter": "biomejs.biome",
  "editor.formatOnSave": true,
  "biome.enabled": true,
  "biome.requireConfiguration": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  }
}

This setup makes Biome your default formatter, enables formatting on save, applies safe fixes on save, and organizes imports when explicitly triggered.

Create or update .vscode/extensions.json:

{
  "recommendations": [
    "biomejs.biome",
    "bradlc.vscode-tailwindcss",
    "ms-vscode.vscode-typescript-next",
    "yzhang.markdown-all-in-one",
    "formulahendry.auto-rename-tag",
    "christian-kohler.path-intellisense"
  ]
}

These extensions pair well with Biome-powered JavaScript, TypeScript, React, and Next.js projects.

Add Useful Scripts

Add Biome scripts to your package.json:

{
  "scripts": {
    "format": "biome format --write .",
    "lint": "biome lint .",
    "lint:fix": "biome lint --write .",
    "check": "biome check .",
    "check:fix": "biome check --write .",
    "ci": "biome ci ."
  }
}

Use these commands during development:

npm run format
npm run lint
npm run check

For CI pipelines, use:

npm run ci

Format, Lint, and Check with Biome

Biome provides separate commands for formatting, linting, and full project checks.

Format Files

npx @biomejs/biome format --write .

Lint Files

npx @biomejs/biome lint .

Lint and Apply Safe Fixes

npx @biomejs/biome lint --write .

Format, Lint, and Organize Imports

npx @biomejs/biome check --write .

Run Biome in CI

npx @biomejs/biome ci .

The biome ci command is designed for continuous integration and helps enforce consistent code quality across your team.

Use Biome with Git Hooks

To catch issues before code is committed, you can run Biome through a Git hook tool such as Husky or Lefthook.

Example with a pre-commit command:

npx @biomejs/biome check --write .

For larger projects, run Biome only on staged files to keep commits fast.

Best Practices for Biome

Use these practices to get the best results from Biome:

  • Keep biome.json as the single source of truth.
  • Install Biome as a project dependency instead of relying only on a global install.
  • Pin the Biome version for consistent formatting across the team.
  • Use the official VS Code extension.
  • Enable format on save.
  • Run biome ci in your deployment pipeline.
  • Use overrides for test files, generated files, config files, and framework-specific files.
  • Keep ignores focused on generated output such as dist, build, .next, and coverage.

When to Use Overrides

Overrides are useful when some files need different linting behavior.

Common examples include:

  • Test files that allow any or console
  • Next.js page and layout files that require default exports
  • Config files that use CommonJS or framework-specific patterns
  • Declaration files that use namespaces
  • Generated files that should not be linted strictly

Using overrides keeps your main rules strict while allowing practical exceptions where needed.

Troubleshooting Biome in VS Code

If Biome does not format or lint correctly in VS Code, check the following:

Make Sure the Extension Is Installed

Install the official extension:

biomejs.biome

Confirm Your Project Has a Biome Config

Biome should find one of these configuration files:

biome.json
biome.jsonc
.biome.json
.biome.jsonc

Check the VS Code Setting Name

Use the latest setting name:

{
  "biome.requireConfiguration": true
}

Avoid older or incorrect setting names such as biome.requireConfig.

Restart the Biome Language Server

Open the VS Code command palette and restart the Biome extension or reload the VS Code window.

Run Biome from the Terminal

If VS Code behaves unexpectedly, confirm Biome works from the CLI:

npx @biomejs/biome check .

If the CLI works but VS Code does not, the issue is likely related to editor settings or workspace configuration.

Conclusion

Biome gives JavaScript and TypeScript teams a fast, modern way to handle formatting, linting, code fixes, import organization, and CI checks from one tool.

With a clean biome.json, the official VS Code extension, format on save, and CI integration, your project can maintain consistent code quality with less configuration overhead.

If you are starting a new React, Next.js, or TypeScript project, Biome is a strong default choice for keeping your codebase clean, fast, and maintainable.