In Laravel, what do url()->current(), url()->full(), url()->previous() and asset() return, and where do their scheme and host come from?
answer
- url() without arguments returns UrlGenerator
- current drops the query string
- previous: Referer header, then session
- ASSET_URL for a CDN root
- APP_URL in console; forceScheme overrides
basics
~20 surl()->current() is the current URL without its query string, url()->full() includes it, url()->previous() uses the Referer header or the session's last URL, and asset() builds a URL to a public file. Scheme and host come from the current request.
solid answer
~40 sCalled without arguments, `url()` returns the `UrlGenerator`. `current()` is the request's URL **without** the query string; `full()` is the same **with** it. `previous($fallback = false)` returns the `Referer` header if present, else the last GET page stored in the session, else the fallback, else the site root. `asset('css/app.css')` builds an absolute URL to a file under `public/`, using `ASSET_URL` as the root when set (a CDN), and adds no cache-busting hash. All of them take scheme and host from the current request; in a console process, such as a queue worker, the request is synthesised from `APP_URL`. `URL::forceScheme('https')` or `URL::forceHttps()` in a service provider forces the scheme of generated URLs.
go deeper
Recall which of current() and full() keeps the query string, that previous() gives the last page, and that asset() points at files in public/.
Explain the lookup order of previous() and where scheme and host come from, including APP_URL for console processes and ASSET_URL for assets.
Anticipate wrong-host links from workers, mixed-content from scheme drift, and the risk of redirecting to a client-supplied Referer.
Set a team convention for absolute links — one configured origin, forced scheme in production, CDN for assets — so URL bugs stop depending on where the code runs.
## `url()` as a helper and as an object Laravel's `url()` helper has two faces: - `url('/pricing')` returns a **string**: an absolute URL built from the current request's scheme and host, such as `https://example.com/pricing`. A value that already looks like a full URL is returned unchanged. - `url()` with no arguments returns the **`Illuminate\Routing\UrlGenerator`** instance, the same object behind the `URL` facade. `url()->current()` and `URL::current()` are the same call. ## The current request: `current()` vs `full()` | Call | For a request to `/reports?page=2` | Query string | |---|---|---| | `url()->current()` | `https://example.com/reports` | dropped | | `url()->full()` | `https://example.com/reports?page=2` | kept | | `request()->path()` | `reports` | dropped, and relative | Use `current()` for canonical links and active-menu checks where the query string is noise; use `full()` when you must return the user to exactly the page they were on, filters and page number included. One subtle difference: `full()` delegates to `$request->fullUrl()`, which reads the incoming request directly, while `current()` goes through the generator and therefore honours `forceScheme`. ## `previous()` and `previousPath()` `url()->previous($fallback = false)` resolves in this order: 1. The **`Referer` header** of the current request, if the browser sent one. 2. Otherwise the URL stored in the session. The session middleware records the full URL of each GET request that matched a route and was not AJAX, a prefetch or a precognitive request. 3. Otherwise `$fallback`, if you passed one. 4. Otherwise the site root. `url()->previousPath()` returns just the path of that URL. Two cautions follow from the order. First, the `Referer` header is **client-controlled**: it can be missing, stripped by a referrer policy, or forged, and an absolute URL is passed through unchanged. Do not treat `previous()` as proof of where a user came from, and be careful redirecting to it after sensitive actions. Second, without a session (API routes) only the header and the fallback remain, so always pass a sensible fallback. ## `asset()` for files in `public/` `asset('images/logo.svg')` returns an absolute URL to a file under the `public/` directory: - The root is **`ASSET_URL`** (config key `app.asset_url`) when it is set — typically a CDN origin — otherwise the request's root. - A leading slash is trimmed, and a path that is already a full URL is returned as-is. - `secure_asset()` forces `https`; `asset($path, true)` does the same. - `asset()` does **no fingerprinting**. Cache-busting for compiled CSS and JS is the job of the Vite integration, not of `asset()`. ## Where scheme and host come from The generator reads the root and the scheme from the request it holds: - **In an HTTP request**, from the request itself: its `Host` and its scheme as the app perceives it. Behind a TLS-terminating proxy, that perception depends on whether the app trusts the proxy's forwarded headers — a separate middleware concern. - **In a console process** — Artisan commands, the scheduler and **queue workers** — there is no browser request, so Laravel creates one from `config('app.url')`, i.e. `APP_URL` (the skeleton's `.env.example` sets `http://localhost:8000`). A queued email built with a wrong `APP_URL` links to the wrong place. - **Overrides**, usually in `AppServiceProvider::boot()`: - `URL::forceScheme('https')` or `URL::forceHttps($this->app->isProduction())` rewrite the scheme of every generated URL. - `URL::useOrigin('https://example.com')` forces the whole root, and `URL::useAssetOrigin()` does the same for `asset()` only. ## Related helpers in the same family - `url()->query('/reports', ['page' => 2])` builds a URL with a query string, merging with any query already in the path. - `secure_url('/pricing')` is `url()` with the scheme forced to `https` for that one call. - `url()->previousPath()` returns only the path of the previous URL, handy for comparisons that must ignore the host. - `url()->isValidUrl($value)` tells you whether a string is already absolute (it accepts `http(s)://`, `//`, `#`, `mailto:`, `tel:` and `sms:` prefixes), which is how `url()` and `asset()` decide to pass it through untouched. ## Common mistakes - Expecting `current()` to keep `?page=2` and losing the pagination state on a redirect. - Hard-coding `http://` in templates and getting mixed-content warnings once the site moves to HTTPS. - Using `previous()` in an API route and getting the site root, because there is no session and no `Referer`. - Building absolute links in a queued job and blaming the queue when `APP_URL` is wrong.
- What does action() generate in Laravel, and what happens when no route points to the given controller method?`action([ReportController::class, 'show'], ['report' => 5])` finds the route registered for that controller action and builds its URL, so the path is not hard-coded. If no registered route uses that action, the generator throws an `InvalidArgumentException` reading "Action … not defined."
- Why do links in emails sent from a Laravel queue worker sometimes point at localhost?A worker is a console process with no incoming HTTP request, so Laravel synthesises one from `APP_URL`. If production still carries a development value such as `http://localhost:8000`, every URL the worker generates — `url()`, `route()`, `asset()`, signed links — uses that root. Set `APP_URL` to the public origin.
saying these in an interview costs you the question
- url()->current() includes the query string
- url()->previous() only reads the session, never a request header
- asset() adds a version hash for cache-busting
- Generated URLs always use APP_URL, even during an HTTP request
- The Referer header is a trustworthy record of where the user came from