šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

Vite Project Structure: index.html, main.tsx, and Config

A guided tour of a Vite React project's file structure: index.html, main.tsx, public vs. src/assets, and vite.config.ts.

⚔ Total XP: 0|šŸ’» react XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

System Hub

Project layout.

Quick Quiz //

Where does a Vite React app actually mount to the DOM?


šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

A scaffolded Vite React project keeps a small, predictable file layout. This lesson walks through what index.html, main.tsx, public/, src/assets, and vite.config.ts each actually do, so the build process stops feeling like a black box.

1The Anatomy of a Vite React Project

Scaffolding a project with the React template produces a small, predictable set of files: index.html at the project root, a typed vite.config.ts, a src/ folder holding application code, and a public/ folder for static assets served without processing.

2index.html Is a Real Entry Point

Unlike older tools that treated the HTML template as a static file injected by the build process, Vite treats the root index.html as part of the actual module graph, containing a direct <script type="module"> reference to the app's entry file that Vite processes like any other source file.

3main.tsx: The Bootstrap File

src/main.tsx is the one place where React is manually attached to the DOM: it imports the root App component and calls createRoot on the #root element referenced in index.html. Everything else in the application is reached through component composition from that single mount point.

4public/ vs. src/assets

Files in public/ are copied to the build output unprocessed, at a fixed, predictable URL — appropriate for things like favicon.ico or robots.txt. Files inside src/, including images, are treated as modules: Vite processes, optimizes, and gives them content-hashed filenames as part of the production build.

5vite.config.ts: The Control Center

vite.config.ts registers plugins like @vitejs/plugin-react, configures dev server behavior, defines path aliases, and tunes production build settings — all in a single typed file, considerably smaller and easier to reason about than a typical multi-file legacy bundler configuration.

6Step-by-Step Breakdown

The Anatomy of a Vite React Project. Running npm create vite@latest with the React template scaffolds a small, predictable set of files: index.html at the project root, a vite.config.ts, a src/ folder with your app code, and a public/ folder for static assets. Understanding what each piece does removes the mystery from the build process.

index.html Is a Real Entry Point. Unlike older tools where public/index.html was a static template injected with a script tag by the build process, Vite treats index.html at the project root as an actual part of the module graph. It contains a <script type="module" src="/src/main.tsx"> tag directly, and Vite processes it like any other source file.

In a Vite project, how does index.html relate to your React app's entry point?

  • →It directly references main.tsx via a module script tag
  • →Vite auto-injects an invisible script the developer never sees

main.tsx: The Bootstrap File. src/main.tsx is where your React app actually mounts. It imports the root App component and calls createRoot to attach it to the #root element defined in index.html. This is the one place in the whole app where React is manually wired into the DOM — everything else is just component composition from here.

public/ vs. src/assets. The public/ folder holds files copied as-is to the output root, unprocessed and unhashed — good for a favicon.ico or robots.txt that needs a fixed URL. Anything inside src/, including images, is treated as a module: Vite processes it, optimizes it, and gives it a content-hashed filename in the production build.

You need a favicon accessible at a guaranteed, unchanging URL like /favicon.ico. Where should the file live?

  • →In the public/ folder
  • →In src/assets, imported as a module

vite.config.ts: The Control Center. vite.config.ts is where you register plugins (like @vitejs/plugin-react), configure the dev server, set up path aliases, and tune the production build. It's a single, typed configuration file — far smaller and easier to reason about than a typical multi-file webpack setup.

Mastery Achieved. You now understand a Vite React project's anatomy: index.html as a real entry point, main.tsx as the single DOM mount location, the public/ vs. src/assets distinction, and vite.config.ts as the central configuration file. Next, you'll learn how to safely manage environment variables across dev, staging, and production.

Level Up šŸš€

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Project structure is a build-time concept, applicable regardless of target browser.

FirefoxSupported

Fully applicable.

SafariSupported

Fully applicable.

EdgeSupported

Fully applicable.

Accessibility (A11y)

1index.html Is the Right Place for Base-Level Meta Tags

Language attributes (lang="en"), a proper viewport meta tag, and a descriptive default <title> belong in the root index.html, since it's the one HTML shell every route ultimately loads into.

SEO Implications

  • 1

    Static Assets in public/ Get Stable, Crawlable URLs

    Files placed in public/ are served at predictable, unhashed paths, which matters for assets like robots.txt, sitemap.xml, or social preview images that external tools and crawlers expect at a fixed location.

Best Practices

Default to src/assets for Anything Imported in Code

Prefer importing images and other assets from within src/ rather than referencing public/ paths by string, since imported assets get automatic optimization, cache-busting hashes, and dead-asset elimination during the build.

Keep vite.config.ts Focused and Well-Commented

As a project grows, the config file accumulates aliases, plugins, and build tweaks — group related settings and comment non-obvious ones so the single source of build truth stays easy to audit.

Frequent Bugs

THE BUG

An image imported from src/assets shows a 404 in the browser after building.

THE FIX

Make sure the import is a proper ES module import (import logo from './logo.png'), not a hardcoded string path — Vite only processes and hashes assets that are actually imported as modules.

THE BUG

A file placed in public/ isn't showing up at the expected root URL.

THE FIX

Files in public/ are served relative to the site root regardless of nesting inside that folder — reference them by absolute path (e.g. /favicon.ico), not a relative path from a component file.

Real-World Examples

Adding a Custom Favicon and Social Preview Image

A team needed a favicon.ico at a guaranteed URL for browser tabs and an og-image.png for social media link previews. Both went into public/ since external tools (browsers, social crawlers) expect fixed, predictable URLs rather than Vite's content-hashed asset filenames.

public/
  favicon.ico
  og-image.png

<!-- index.html -->
<link rel="icon" href="/favicon.ico" />
<meta property="og:image" content="/og-image.png" />

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Referencing a src/assets image by a hardcoded string path instead of importing it

// Wrong <img src="/src/assets/logo.png" /> // Correct import logo from './assets/logo.png'; <img src={logo} />

The Solution //

Vite only processes and hashes assets that are imported as ES modules. A hardcoded string path like '/src/assets/logo.png' bypasses that processing and will typically 404 in the production build.

The Error //

Deleting or renaming #root in index.html without updating main.tsx

<!-- index.html --> <div id="app-root"></div> // main.tsx must match createRoot(document.getElementById('app-root')!).render(<App />);

The Solution //

createRoot(document.getElementById('root')) will fail at runtime if the id doesn't match what's actually in index.html. Keep the id used in main.tsx's getElementById call in sync with the element's id in index.html.

Lesson Glossary

[01]index.html (Vite)

The root HTML file, treated as part of Vite's module graph rather than a static template.

Code Preview
<script type="module" src="/src/main.tsx">

[02]main.tsx

The bootstrap file where React is manually mounted to the DOM via createRoot.

Code Preview
createRoot(el).render(<App />)

[03]public/

A folder for static assets copied unprocessed to the build output at fixed URLs.

Code Preview
public/favicon.ico

[04]src/assets

A conventional folder for images and static files imported as processed, hashed modules.

Code Preview
import logo from './assets/logo.png'

[05]vite.config.ts

The single typed configuration file for plugins, dev server settings, aliases, and build options.

Code Preview
defineConfig({ plugins: [react()] })

Continue Learning