Laravel's built-in development server serves the app correctly without /public ever appearing in the URL — the "public in the URL" problem only shows up when deploying to Apache or another web server pointed at the project root instead of the public/ folder specifically.
The correct fix: point the document root at public/
The actual recommended solution is to configure the web server's document root (or, on shared hosting, the domain's "Document Root" setting in the control panel) to point directly at the project's public/ folder — not the project root. This is the approach every production Laravel deployment guide recommends, because it also keeps the rest of the application (including .env) outside the web-accessible directory entirely, which matters for security independent of the URL cosmetics.
# Apache virtual host example
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/example.com/public
</VirtualHost>
If you can't change the document root (shared hosting without that control)
A root-level .htaccess that rewrites requests into public/ is the fallback:
# .htaccess in the project root
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)$ public/$1 [L]
</IfModule>
This works, but it's genuinely a workaround, not the recommended pattern — it doesn't isolate .env and the rest of the app from being in a web-accessible directory the way pointing the document root at public/ does.
Why not just move everything out of public/?
Some older guides suggest moving the contents of public/ up into the project root and adjusting the paths in index.php accordingly. This works but is fragile — it's easy to break on a Composer update or Laravel upgrade that touches those paths, and it inverts the security model (everything is now web-accessible by default, rather than only the explicitly public folder). Not recommended for a real deployment.
The takeaway
If you control the server configuration (a VPS, a dedicated box, most cPanel setups with subdomain/addon-domain document root control), set the document root to public/ directly — it's simpler and more secure than either alternative.