Skip to content
Docs

Shared configs

Besides templates, the package ships three extendable configs — TypeScript, Oxlint, and Oxfmt — so every Fusion Stack project type-checks, lints, and formats the same way. Extend them from the package and override locally only where a project genuinely differs.

All three assume the package is installed (see Setup), plus the tools themselves:

bun add -D oxlint oxfmt @typescript/native-preview

TypeScript

tsconfig.json can extend npm packages natively. The base enables strict (plus noUncheckedIndexedAccess and friends), bundler-style module resolution, and the latest lib/target — everything except runtime-specific settings, which stay per-project:

tsconfig.json
{
	"extends": "@tikab-interactive/fusion-config/tsconfig.json",
	"compilerOptions": {
		"types": ["bun"] // runtime types are deliberately not in the base
	},
	"include": ["src"]
}

Anything you set in local compilerOptions wins over the base.

Oxlint

The base is aggressive on purpose: correctness and suspicious report as errors, perf and pedantic as warnings, with the typescript, unicorn, oxc, react, jsx-a11y, import, and promise plugins active. Tests, e2e, scripts, and stories (**/*.test.*, **/*.spec.*, **/e2e/**, **/scripts/**, **/*.stories.*) are exempt from size rules and no-await-in-loop, and .tsx files get relaxed size limits since JSX composition inflates line counts. A few rules are pre-tuned — for example eqeqeq is an error, except x == null, which deliberately covers both null and undefined.

Create an oxlint.config.ts (requires a Node runtime ≥ 22.18; a directory can have either this or .oxlintrc.json, not both):

oxlint.config.ts
import config from "@tikab-interactive/fusion-config/oxlint";
import { defineConfig } from "oxlint";
 
export default defineConfig({
	extends: [config],
	// ignorePatterns does NOT inherit through `extends` (root-config-only,
	// like ESLint) — it must live here, in the project's own config.
	ignorePatterns: ["**/node_modules"],
});

Project-specific tuning goes next to extends and wins over the base. Keep a short comment on why each deviation exists:

oxlint.config.ts
export default defineConfig({
	extends: [config],
	ignorePatterns: ["**/node_modules"],
	rules: {
		// Drizzle's relational-query callbacks shadow the imported
		// `eq`/`and` operators by design.
		"no-shadow": "off",
	},
});

Prefer JSON? extends in .oxlintrc.json only accepts relative paths (package imports are not supported in the JSON format), but a path into node_modules works:

.oxlintrc.json
{
	"extends": ["./node_modules/@tikab-interactive/fusion-config/configs/oxlint.json"],
	"ignorePatterns": ["**/node_modules"]
}

Oxfmt

Oxfmt has no extends mechanism yet (oxc#16394), so the shared config is imported and re-exported instead — spread it and put overrides after:

oxfmt.config.ts
import config from "@tikab-interactive/fusion-config/oxfmt";
 
export default {
	...config,
	// project-specific overrides go here
};

The base formats with tabs, with one carve-out: package.json stays 2-space-indented so the formatter never fights bun add, which rewrites the file that way.

Scripts

Wire everything up once (tsgo is the native TypeScript preview — substitute tsc if the project uses stock TypeScript):

package.json
{
	"scripts": {
		"typecheck": "tsgo --noEmit",
		"lint": "oxlint",
		"fmt": "oxfmt",
		"fmt:check": "oxfmt --check"
	}
}