Dev Kraken LogoDev Kraken
  • Home
  • Blog
  • Resume

© 2024 Dev Kraken.

  • X (Twitter)
  • Linkedin
  • Github
  • Sitemap

Configure Biome for JavaScript & TypeScript in VS Code

Learn how to configure Biome in VS Code for JavaScript, TypeScript, and React. Improve formatting, linting, and productivity with biome.json and extensions.

Dev Kraken Logo

Dev Kraken

Published on October 2, 2025
Biome VS Code setup

Introduction

When working on modern JavaScript and TypeScript projects, having consistent code style, fast linting, and automated formatting is crucial. That’s where Biome comes in.

Biome is a next-generation formatter, linter, and static analysis tool built for performance and reliability. Unlike ESLint and Prettier, which often require multiple configurations, Biome provides an all-in-one solution.

In this guide, we’ll cover:

  • What Biome is and why you should use it
  • How to configure biome.json for your project
  • Recommended VS Code settings for Biome integration
  • Extensions to supercharge your workflow

Why Use Biome Over ESLint + Prettier?

Many developers are migrating from the traditional ESLint + Prettier setup to Biome because:

  • 🚀 Performance: Biome is written in Rust, making it significantly faster.
  • 🔧 Simplicity: One config file (biome.json) instead of multiple tools.
  • 🛡 Built-in lint rules: Covers style, correctness, complexity, security, a11y, and performance.
  • 🎯 Future-proof: Actively maintained with modern JS/TS and React support.

Setting Up biome.json

Your biome.json file is the core configuration for Biome. Below is an example setup optimized for Next.js, React, TypeScript, and CSS projects:

{
  "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true,
    "defaultBranch": "main"
  },
  "files": {
    "ignoreUnknown": true,
    "includes": [
      "**/*.js",
      "**/*.jsx",
      "**/*.ts",
      "**/*.tsx",
      "**/*.json",
      "**/*.css",
      "**/*.scss"
    ],
    "experimentalScannerIgnores": [
      "**/node_modules/**",
      "**/.next/**",
      "**/dist/**",
      "**/build/**",
      "**/coverage/**",
      "**/.turbo/**",
      "**/out/**",
      "**/.env*",
      "**/public/**",
      "**/*.d.ts",
      "**/storybook-static/**",
      "**/.vercel/**"
    ]
  },
  "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 config enforces clean code rules, strict typing, accessibility (a11y) checks, and modern best practices.

VS Code Configuration for Biome

To make Biome your default formatter and linter in VS Code, add the following settings to your .vscode/settings.json:

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

🔑 Pro Tip: Set "files.autoSave": "onFocusChange" to avoid losing unsaved changes when switching between files.

Recommended Extensions

To maximize productivity, here are the recommended VS Code extensions for Biome-powered projects:

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

Best Practices for Biome

✅ Use biome.json as the single source of truth – no need for ESLint or Prettier.

✅ Integrate with Git hooks (via Husky or Lefthook) to auto-fix issues before committing.

✅ Run Biome in CI/CD pipelines to enforce consistent code quality.

✅ Leverage overrides in biome.json for test files, configs, and special cases.

Conclusion

Biome is becoming the go-to alternative to ESLint and Prettier, offering speed, simplicity, and full-featured linting out of the box. With the biome.json configuration, proper VS Code setup, and recommended extensions, your team can maintain consistent, high-quality code with minimal effort.

If you’re starting a new project or modernizing an existing one, now is the perfect time to switch to Biome.