When developing custom modules or themes in Drupal, you often need to retrieve the site's base URL or specific hostname. While functions like base_path() are useful for getting the subdirectory where Drupal is installed, they don't provide the full domain name (e.g., example.com).
Whether you are building absolute links for an external API, generating metadata, or handling redirects, knowing the correct way to access the request information is vital. In this guide, we will explore the different methods to retrieve the base URL and hostname in Drupal, ranging from quick static calls to the recommended Dependency Injection approach.
Using the Request Object
The most direct way to get the hostname is through the Symfony Request object. Drupal provides a static wrapper to access the current request, which allows you to pull the host or the full scheme and host.
To get just the hostname (e.g., drupal8.local):
$host = \Drupal::request()->getHost();
If you need the full URL including the protocol (e.g., https://drupal8.local):
$host = \Drupal::request()->getSchemeAndHttpHost();
A Note on Static Access
While \Drupal::request() is convenient, it is generally discouraged in production-grade code. Accessing the request directly can cause issues when running code from the command line (CLI), inside queue processors, or during automated tests where a global request object might not exist.
The Recommended Approach: Dependency Injection
For most services, controllers, or forms, you should use Dependency Injection (DI). This ensures your code is testable and robust. If you are working within a form that extends FormBase, the request is already available to you:
$host = $this->getRequest()->getSchemeAndHttpHost();
If you are building a custom service or a controller, you should inject the request_stack service. Here is how you can implement it using the RequestStack class:
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\DependencyInjection\ContainerInterface;
protected $request;
public function __construct(RequestStack $request_stack) {
$this->request = $request_stack->getCurrentRequest();
}
public static function create(ContainerInterface $container) {
return new static(
$container->get('request_stack')
);
}
// Usage
$host = $this->request->getHost();
$fullUrl = $this->request->getSchemeAndHttpHost();
Using the Drupal Url Class
Sometimes, the best way to get the base URL is to ask Drupal for the absolute URL of the front page. This method is often preferred because it respects language prefixes and site configurations. This is effectively how Drupal generates the [site:url] token.
use Drupal\Core\Url;
$url_options = [
'absolute' => TRUE,
'language' => \Drupal::languageManager()->getCurrentLanguage(),
];
$site_url = Url::fromRoute('<front>', [], $url_options)->toString();
Alternatively, you can get the absolute base path from user input:
$url = \Drupal\Core\Url::fromUserInput('/', ['absolute' => TRUE])->toString();
Legacy and Global Alternatives
In some edge cases, you might find yourself working in a context where the Drupal container isn't fully available, or you are working with legacy procedural code. You can use the global $base_url variable combined with PHP’s parse_url() function:
global $base_url;
$base_url_parts = parse_url($base_url);
$host = $base_url_parts['host'];
While this works, it is generally better to stick to the RequestStack or Url class methods in modern Drupal development.
Wrapping Up
Choosing the right method depends on your specific context:
- For quick debugging: Use \Drupal::request()->getHost().
- For Controllers and Services: Use Dependency Injection with request_stack.
- For generating site-wide links: Use Url::fromRoute('<front>', ...) to ensure language and configuration settings are respected.
By following these patterns, you ensure your Drupal site remains maintainable, testable, and compatible with both web and CLI environments.