Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Site Alias Laravel Package

consolidation/site-alias

Site Alias lets Laravel apps give each site its own domain aliases and resolve the correct site from the incoming request, with support for multiple aliases per site and fast lookup caching.

Deep Wiki
Context7

Getting Started

consolidation/site-alias is the alias engine that powers Drush and Pantheon Terminus. It does one job: turn a string like @mysite.dev into a structured, validated record describing a site (local path, remote host, SSH user, URI, file paths) so that other code can build commands against it.

composer require consolidation/site-alias

Where to look first, in this order:

  1. SiteAliasManager — the entry point. It resolves alias names to records and holds the @self alias.
  2. SiteAliasFileLoader (with SiteAliasFileDiscovery) — reads YAML files off disk from a configurable search path.
  3. SiteAlias / AliasRecord — the value objects. SiteAlias is the raw data; AliasRecord pairs that data with the name it was resolved from (and proxies get()/set()/root()/uri() down to the SiteAlias).

First use case: read a site's root and URI out of a YAML alias file and use it to locate a docroot.

# drush/sites/example.site.yml
dev:
  host: dev.example.com
  user: deploy
  root: /var/www/dev/docroot
  uri: https://dev.example.com
use Consolidation\SiteAlias\SiteAliasFileLoader;
use Consolidation\SiteAlias\SiteAliasManager;

$loader = (new SiteAliasFileLoader())->addSearchPath(__DIR__ . '/drush/sites');
$manager = new SiteAliasManager($loader);

$record = $manager->get('@example.dev');   // null if not found
if ($record === null) {
    throw new \RuntimeException('Unknown alias');
}

print $record->get('root');                // /var/www/dev/docroot
print $record->isRemote() ? 'remote' : 'local';

That null check is not optional — see the Gotchas section.

Implementation Patterns

Define aliases as grouped YAML files

The filename prefix becomes the alias namespace, so example.site.yml with a key dev yields @example.dev. Put shared values at the top level and per-environment overrides beneath; the loader handles self specially so you can write self.site.yml and get @self plus @group.self.

# drush/sites/example.site.yml
common:
  user: deploy
  paths:
    files: sites/default/files
  ssh:
    options: '-o StrictHostKeyChecking=no'

dev:
  host: dev.example.com
  root: /var/www/dev/docroot
  uri: https://dev.example.com

prod:
  host: prod.example.com
  root: /var/www/prod/docroot
  uri: https://example.com

Other keys you will actually use: os (Windows remotes), php, command (per-command option overrides), env-vars, and paths (arbitrary named paths that downstream code resolves against root).

Wire the manager once, configure search paths before resolving

Treat the manager as immutable for the life of a command. Add all search paths up front, then resolve. Search-path order determines precedence when two files define the same alias.

$loader = new SiteAliasFileLoader();
$loader->addSearchPath($projectRoot . '/drush/sites');  // project wins
$loader->addSearchPath($home . '/.drush/sites');        // user fallback

$manager = new SiteAliasManager($loader);

Inject via the aware interface in framework commands

If you are writing Drush commands (or any container-wired CLI), implement SiteAliasManagerAwareInterface and use SiteAliasManagerAwareTrait. The container inflector calls setSiteAliasManager() for you, and $this->siteAliasManager() is available inside execute().

class StatusCommand extends DrushCommands implements SiteAliasManagerAwareInterface
{
    use SiteAliasManagerAwareTrait;

    public function execute(string $alias): void
    {
        $record = $this->siteAliasManager()->get($alias);
        // ...
    }
}

Fan out over alias groups

getMultiple('@example.*') returns an array keyed by alias name and is the clean way to implement "run this against every environment" commands. Pair it with remotes() when you want to exclude @self and anything else without a host.

foreach ($manager->getMultiple('@example.*') as $name => $record) {
    if (!$record->isRemote()) {
        continue;
    }
    $this->runOn($record);
}

Build the SSH/rsync command from the record, do not hand-roll it

The whole point of the package is that command construction is centralized. Read host, user, root, uri, and ssh.options off the record rather than parsing alias strings yourself.

$ssh = sprintf(
    'ssh %s %s@%s',
    $record->get('ssh.options') ?? '',
    $record->get('user'),
    $record->get('host')
);

Override @self for tests and embedded use

@self is normally synthesized from the current working directory. When you embed the manager in a library or a test, set it explicitly so behavior does not depend on getcwd().

$manager->setSelf(SiteAlias::create([
    'root' => '/tmp/fixture/docroot',
    'uri'  => 'http://localhost:8080',
]));

Round-trip alias data to subprocesses

export() returns the underlying array, which is what you want to hand to a child process (serialize it, or pass it as --define-style options). The child can rebuild an identical SiteAlias::create($data), which keeps alias semantics consistent across process boundaries instead of re-parsing YAML in two places.

Gotchas and Tips

get() returns null for unknown aliases — it does not throw. Every call site needs a null check; a missing alias should produce your own clear error message, not a fatal "call to a member function on null" three frames deeper.

@self is synthesized, not required. If no self.site.yml exists, the manager still produces a usable @self pointing at the cwd. This surprises people who expect a "no aliases defined" error. If you need a defined self, check has('@self') explicitly or compare fields against the synthesized value.

Filename prefix vs. key confusion is the #1 support question. foo.site.yml containing key bar is @foo.bar, not @bar and not @foo. Legacy Drush 8–style .alias.yml files in a drush/ directory use bare @name keys with no prefix — if the same site is reachable under two different alias spellings, you have a mix of legacy and modern files on the search path.

Path precedence is silent. Two files defining the same alias do not error; the earlier search path simply wins. When an alias "won't update," verify which file actually loaded before editing anything. drush sa --format=json @example.dev dumps the fully-resolved record and is the fastest way to see the effective values, including everything inherited from top-level keys.

Malformed YAML surfaces as an exception, usually at first resolution rather than at construction, because loading is lazy. A typo in a prod block that nothing references yet will not fail until someone targets @prod. Lint your alias files in CI.

Do not change search paths after the first lookup. Configuration added mid-command may not take effect and, worse, may take effect for some aliases and not others. Build the loader, then the manager, then resolve — in that order.

No environment-variable interpolation in YAML. Alias files are static data. If you need a hostname from $_ENV or a CI variable, construct the SiteAlias in code and register it with add(), or generate the file before invoking the tool.

add() argument order has shifted between versions. When registering programmatic aliases, check the signature in the installed version rather than trusting an older example. setSelf() is stable and covers most cases.

Extension points worth knowing: swap in a custom loader by constructing SiteAliasManager with your own loader implementation (useful for database-backed or API-backed alias sources, e.g. a hosting provider's environment list); and prefer injecting the manager via SiteAliasManagerAwareInterface over new SiteAliasManager() inside a command, so tests can substitute a manager pre-loaded with fixtures.

Testing recipe: build a SiteAliasManager with a SiteAliasFileLoader pointed at a fixture directory containing one .site.yml, then assert on get('@fixture.dev')->export(). If you need to test alias-less code paths, setSelf() to a temp directory and skip files entirely.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource