Laravel vite production doesn't use https
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
The HTTPS Dilemma: Why Vite Assets Don't Automatically Use HTTPS in Laravel Production
As a senior developer working with modern PHP stacks like Laravel, we often encounter subtle but frustrating issues when moving from local development to production environments. One common pitfall involves asset loading, especially when dealing with mixed content warnings caused by protocol mismatches (HTTP vs. HTTPS).
You've hit a classic scenario: your local development setup using npm run dev works perfectly fine, but when you deploy the built assets using npm run build on an HTTPS-served domain, your Blade view still references assets via http://, causing the browser to flag mixed content errors.
This post will dive deep into why this happens and outline the necessary steps—focusing on environment configuration and asset path management—to ensure Vite correctly bundles and links assets using the correct protocol in a production Laravel application.
Understanding the Root Cause: Build vs. Serve Context
The discrepancy you are seeing stems from the difference between how Vite handles asset paths during development versus how the final web server resolves those paths in production.
When you run npm run dev, Vite often serves assets directly from memory or a local development server, which is why it seems seamless locally. However, when you run npm run build, Vite generates static files (CSS, JS) into the public directory, and Laravel's Blade engine uses the helper functions—like asset()—to generate URLs.
The core problem often lies not within Vite’s configuration itself, but in how your web server (Nginx/Apache) is configured to handle SSL termination and how Laravel resolves asset paths relative to the host protocol.
Investigating Vite Configuration for Production
Let's review your provided setup. Your vite.config.js looks standard:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
],
server: {
host: true,
hmr: {
host: 'localhost'
}
},
});
The server block is crucial for the development server setup (handling Hot Module Replacement), but it generally does not dictate the public URL protocol for the final production build. Vite builds files based on the context provided by Laravel and the directory structure.
There are no specific environment variables within Vite that force the output to use HTTPS. Vite focuses on bundling code; the web server layer handles the protocol enforcement.
The Solution: Server, Environment, and Asset Path Management
To resolve this mixed content issue, we need to look at three critical areas: the server setup, Laravel's asset helpers, and environment variables.
1. Ensure Proper SSL Configuration on the Web Server
The most common fix is ensuring your web server (e.g., Nginx or Apache) is correctly configured to listen on port 443 and serve all traffic via HTTPS, and that there are no conflicting redirects causing assets to revert to HTTP during the build phase evaluation.
If you are using a proxy like Nginx, ensure your server block explicitly handles the SSL configuration for the entire domain. Good practices in the Laravel ecosystem emphasize secure deployment, as discussed on laravelcompany.com.
2. Leveraging Laravel's Asset Helpers Correctly
When you use the @vite Blade directive:
@vite(['resources/css/app.css', 'resources/js/app.js'])
Laravel dynamically injects the correct path based on the current request URL, which is usually fine if the base URL is correctly set to HTTPS in your web server configuration.
If you are manually constructing asset links using asset(), ensure that Laravel detects the current protocol correctly:
// This should resolve to https://yourdomain/css/app.css if the request is secure
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
3. Environment Variables for Protocol Consistency (Advanced)
While there isn't a direct Vite variable for this, you can manage protocol-related settings via your .env file, which influences how Laravel constructs URLs:
APP_URL=https://yourdomain.com
Setting APP_URL correctly ensures that any URL generated by Laravel helpers defaults to the secure protocol defined in the environment variables. When Vite bundles assets, they are typically referenced relative to this base URL context provided by Laravel's framework layer.
Conclusion
The absence of HTTPS in your production build is almost always a symptom of an external configuration issue—specifically, how your web server handles SSL and how asset paths are resolved during the serving process—rather than a flaw in the Vite bundling mechanism itself.
By ensuring your Nginx/Apache setup enforces HTTPS across the board and by correctly setting APP_URL in your .env, you establish the necessary context for Laravel and Vite to generate fully secure, protocol-aware asset links. Always prioritize secure deployment practices; this layered approach ensures that assets are not just bundled correctly but are served securely to the end-user.