Images, fonts, and other assets return 404 errors after deploying a Lovable project because their file paths are wrong in the built output. Fix this by placing all assets in the /public folder, using root-relative paths starting with / in your code, verifying the Vite base path in vite.config.ts is correct, and clearing CDN caches after deployment. Assets in /src are processed by Vite and get hashed filenames, while assets in /public are copied as-is.
Why asset paths break when deploying Lovable projects
Lovable projects use Vite as the build tool, which handles assets differently depending on where they are stored. Files in the /public folder are copied directly to the build output with their original names and paths. Files in /src are processed by Vite, which adds content hashes to filenames (like logo-a3b4c5d.png) for cache busting. Asset 404s happen when your code references a path that does not exist in the deployed build. Common scenarios include: using relative paths (./images/logo.png) instead of root-relative paths (/images/logo.png), referencing /src assets with their original names instead of the hashed versions, or setting an incorrect base path in vite.config.ts. This problem is invisible in the Lovable preview because the development server resolves paths differently than a production server. An asset that works perfectly in preview may return 404 after deployment if the path is not configured for production.
- Assets are in /src instead of /public, so Vite hashes the filenames and the original paths no longer work
- Code uses relative paths (./image.png) that break when accessed from nested routes
- The base path in vite.config.ts is set incorrectly for the hosting platform
- CDN or hosting platform serves cached versions of old assets while the new build references new hashed filenames
- Asset files were not committed to GitHub and are missing from the deployed build
Error messages you might see
GET https://myapp.lovable.app/images/logo.png 404 (Not Found)The browser cannot find the image at the expected path. The file may be missing from the /public folder, or the path in your code does not match the actual file location in the build output.
Failed to load resource: the server responded with a status of 404A generic 404 for any asset (image, font, JSON file). Check the exact URL in the error to determine which file is missing and where the browser expects to find it.
Module not found: Can't resolve './assets/image.png'Vite cannot find the referenced file during the build process. Either the file does not exist at the specified path, or the path contains a typo. Check the actual file location and update the import.
Before you start
- A Lovable project deployed to an external hosting platform where assets are not loading
- Access to the browser developer tools (Network tab) to identify which assets return 404
- Dev Mode or GitHub access to check where files are actually located in the project
How to fix it
Move assets to the /public folder for direct serving
Files in /public are copied to the build output as-is, preserving their original paths
Move assets to the /public folder for direct serving
Files in /public are copied to the build output as-is, preserving their original paths
Open your project in Dev Mode or through the GitHub repository. Check where your assets currently live. If images, fonts, or other static files are in /src/assets, they get processed by Vite and receive hashed filenames. Move them to /public instead. Files in /public/images/logo.png become available at /images/logo.png in the deployed app. This is the simplest and most reliable approach for static assets.
// File location: src/assets/images/logo.png// Import in code:import logo from "./assets/images/logo.png";// This works in dev but the hashed filename may cause issues// File location: public/images/logo.png// Reference in code (no import needed):<img src="/images/logo.png" alt="Logo" />// The file is served directly at /images/logo.pngExpected result: The image loads correctly at /images/logo.png in both preview and production deployments.
Use root-relative paths for all asset references
Root-relative paths (/path) work from any route, while relative paths (./path) break on nested routes
Use root-relative paths for all asset references
Root-relative paths (/path) work from any route, while relative paths (./path) break on nested routes
Replace all relative asset paths with root-relative paths starting with /. A relative path like ./images/logo.png resolves differently depending on the current URL. If the user is on /dashboard/settings, the browser looks for /dashboard/settings/images/logo.png, which does not exist. A root-relative path /images/logo.png always resolves to the same location regardless of the current route.
// Relative path — breaks on nested routes<img src="./images/logo.png" alt="Logo" /><img src="images/hero.jpg" alt="Hero" /><link rel="stylesheet" href="styles/custom.css" />// Root-relative paths — work from any route<img src="/images/logo.png" alt="Logo" /><img src="/images/hero.jpg" alt="Hero" /><link rel="stylesheet" href="/styles/custom.css" />Expected result: Assets load correctly regardless of which page or route the user is viewing.
Verify the Vite base path configuration
An incorrect base path in vite.config.ts causes all asset URLs to be prefixed with the wrong path
Verify the Vite base path configuration
An incorrect base path in vite.config.ts causes all asset URLs to be prefixed with the wrong path
Open vite.config.ts in your project. Check the base property. For most deployments, this should be '/' (the default). If you are deploying to a subdirectory (like github.io/my-project/), set base to '/my-project/'. An incorrect base path is one of the most common causes of asset 404s after deployment because it prepends the wrong prefix to every asset URL in the built HTML.
// vite.config.ts — incorrect base pathexport default defineConfig({ base: '/wrong-path/', plugins: [react()],});// vite.config.ts — correct base path for root deploymentexport default defineConfig({ base: '/', plugins: [react()],});Expected result: Asset URLs in the built HTML start with / (or your correct subdirectory path), matching the actual server structure.
Clear CDN caches and verify the build output
CDN caching can serve old asset references while the new build expects new filenames
Clear CDN caches and verify the build output
CDN caching can serve old asset references while the new build expects new filenames
After deploying, clear any CDN or hosting caches. On Vercel, deployments automatically invalidate the cache. On Netlify, go to Site settings > Build & deploy > Post processing and clear the cache. On Cloudflare, purge the cache. Then check the build output: in the dist/ folder, verify that all expected assets exist. Open the browser's Network tab and look for any 404 responses on asset requests. If debugging asset paths across multiple deployment environments gets complex, RapidDev's engineers have resolved asset issues across 600+ Lovable projects.
// Old deployment serves: logo-abc123.png// New deployment references: logo-def456.png// CDN still serves the old page pointing to the old hash// After cache clear:// Browser requests logo-def456.png// Server returns the correct new file// No 404 errors in the Network tabExpected result: All assets load correctly with no 404 errors in the browser's Network tab.
Complete code example
1import { defineConfig } from "vite";2import react from "@vitejs/plugin-react-swc";3import path from "path";45export default defineConfig({6 // Base path: '/' for root deployment, '/subdir/' for subdirectory7 base: "/",8 plugins: [react()],9 resolve: {10 alias: {11 "@": path.resolve(__dirname, "./src"),12 },13 },14 build: {15 // Output directory for the production build16 outDir: "dist",17 // Generate source maps for debugging (optional)18 sourcemap: false,19 // Asset handling20 assetsDir: "assets",21 // Inline assets smaller than 4kb as base6422 assetsInlineLimit: 4096,23 rollupOptions: {24 output: {25 // Organize built assets into subdirectories26 assetFileNames: "assets/[name]-[hash][extname]",27 chunkFileNames: "assets/[name]-[hash].js",28 entryFileNames: "assets/[name]-[hash].js",29 },30 },31 },32});Best practices to prevent this
- Place all static assets (images, fonts, icons) in the /public folder for predictable paths in production
- Always use root-relative paths starting with / for assets in /public — never use relative paths
- For assets imported in JavaScript (icons used as React components), keep them in /src and use import statements
- Set the base path in vite.config.ts to match your deployment URL structure — '/' for root, '/subdir/' for subdirectories
- After deployment, check the browser Network tab for 404 errors to identify any missing assets
- Commit all asset files to GitHub before deploying — files not in the repo will not be in the build
- Use Supabase Storage for user-uploaded files instead of the /public folder — these survive across deployments
- Clear hosting platform caches after deploying if asset URLs have changed
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
My Lovable project shows broken images and missing assets after deploying to [Vercel/Netlify/other]. The assets work in Lovable's preview but return 404 in production. Here is my project structure: [paste file tree showing where assets are located] And here is my vite.config.ts: [paste vite config] Please: 1. Identify which assets need to be moved to /public 2. Update all asset references to use root-relative paths 3. Check if the vite.config.ts base path is correct for my deployment 4. List any assets that are missing from the repository
Fix broken asset paths in my deployed app. Move all static images from @src/assets/ to the /public/images/ folder. Update every reference to these images across all components to use root-relative paths like /images/filename.png instead of import statements. Check that @vite.config.ts has base set to '/' for root deployment. Do not change any component functionality — only update asset paths.
Frequently asked questions
Why do my images work in Lovable preview but not after deployment?
The development server resolves paths differently than a production server. Relative paths like ./images/logo.png work in preview because the dev server tries multiple locations. In production, the path must match exactly. Move assets to /public and use root-relative paths like /images/logo.png.
Should I put assets in /public or /src in a Lovable project?
Use /public for static assets you reference by URL (images in HTML, favicon, fonts). Use /src for assets you import in JavaScript (SVG icons used as React components). Files in /public keep their original paths; files in /src get hashed filenames.
What is the Vite base path and when should I change it?
The base property in vite.config.ts sets the prefix for all asset URLs in the built HTML. Keep it as '/' for standard deployments. Change it only if deploying to a subdirectory, like '/my-project/' for GitHub Pages.
How do I find which assets are returning 404 after deployment?
Open the browser developer tools, go to the Network tab, and reload the deployed page. Filter by status code or look for red entries. Each 404 shows the exact URL the browser tried to load, helping you identify the broken path.
Do I need to clear the CDN cache after deploying?
Sometimes. Vite adds content hashes to filenames, so new builds get new URLs that bypass caches. But if your HTML file is cached, it may still reference old asset hashes. On Vercel, caches are cleared automatically. On other platforms, you may need to purge manually.
What if I can't fix this myself?
If your deployment has many broken asset paths across different components and hosting configurations, RapidDev's engineers can audit and fix all of them. They have resolved asset path issues across 600+ Lovable deployments.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your issue.
Book a free consultation