Skip to content

Guide to File Extensions in React Projects

Four extensions are in common use in a React codebase. The choice between them is a convention rather than a constraint — the bundler is configured to resolve all four — but it carries information to the reader and, for the TypeScript pair, to the compiler.

.js — plain JavaScript. Universally understood by tooling and, for module scripts, runnable in a browser without a build step. It offers no static type checking, and a .js file containing JSX needs the toolchain configured to transform it, which Vite and the CRA-era react-scripts both do by default.

.jsx — JavaScript containing JSX. The extension does the work of distinguishing components from plain utility modules at a glance. It still requires transpilation and still has no type checking.

.ts — TypeScript without JSX. Static type checking, and markedly better editor support: autocompletion, reliable rename, find-references that follows types rather than text. The costs are a compilation step and the learning curve of the type system.

.tsx — TypeScript containing JSX. The combination most React component code is written in today: typed props and state on top of JSX. Note that .tsx changes how the compiler reads angle brackets — the <T> type-assertion syntax is unavailable, and as T is used instead.

For a new project, .tsx for components and .ts for everything else gives the full benefit of TypeScript across the codebase.

For an existing JavaScript project, .js or .jsx remains the right answer unless there is a decision to migrate. TypeScript supports mixed codebases, so a migration can proceed file by file, converting to .ts/.tsx as each module is touched.

Consistency within a project matters more than which convention is chosen. Mixing .js and .jsx for the same kind of file loses the signal the extension was meant to carry.