Search by

lauroguedes / laravel-astro-landing

lauroguedes

Keep an Astro landing page in the same repository as your Laravel application, scaffold it with one command, run it alongside `composer run dev`, and deploy it on its own.

v1.2.0 2026-10-11 17:11 UTC

This package is auto-updated.

Last update: 2026-10-13 06:49:03 UTC


README

Tests Latest Version Downloads License

Keep an Astro landing page in the same repository as your Laravel application, and deploy it somewhere else.

Laravel + Astro Glassmorphism Banner

A product's marketing site and the product itself change for different reasons and belong on different servers: the landing is static, cheap to host on a CDN and edited by whoever writes the copy; the application needs PHP, a database and a deploy that runs migrations. Keeping them in one repository keeps them in sync (same pull requests, same issues, and a landing that links to the routes that actually exist), as long as nothing couples them.

This package is the decoupling, set up in one command:

  • landing:install creates the Astro project in landing/ from an empty template, an official example, any template repository, or a free theme from the Astro themes catalog.
  • composer run dev starts the landing next to the application (Laravel 13.16+).
  • landing:workflow writes a GitHub Actions workflow that builds and deploys the landing to Cloudflare Pages, Netlify, Vercel, GitHub Pages or your own server, and runs only when the landing changed.

Installation

composer require lauroguedes/laravel-astro-landing --dev
php artisan landing:install

It is a development dependency: nothing in it runs on the server that serves your application. The landing is deployed by GitHub Actions, not by PHP.

landing:install asks where the landing lives, what it starts from, which package manager to use, where it deploys, where visitors will reach it, and whether the application's home page should send them there (plus, for an empty project, which integrations to add). Then it runs create-astro, installs the dependencies and wires the rest:

 ┌ What should the landing start from? ─────────────────────────┐
 │ › ● An empty project: Astro's minimal template               │
 │   ○ An official Astro example                                │
 │   ○ A template repository on GitHub, GitLab or Bitbucket     │
 │   ○ A free theme from astro.build/themes                     │
 └──────────────────────────────────────────────────────────────┘
What it does Why
Creates landing/ with create-astro Its own package.json, lockfile and build
Publishes config/landing.php Where the landing is, for every other command
Adds landing/node_modules, dist, .astro to .gitignore Not every template ignores them
Adds @source not '../../landing'; to resources/css/app.css Tailwind v4 scans the whole project and would put the landing's classes in the application's CSS
Writes .github/workflows/deploy-landing.yml If you chose a deploy target
Adds LANDING_URL to .env and .env.example So the application knows where the landing is
Points / in routes/web.php at LANDING_URL If you asked; see Domains and routes
Sets base in the landing's astro.config If the landing is served under a path

Nothing that exists is overwritten without --force, and .gitignore and app.css are only ever appended to.

Starting from a template

php artisan landing:install --template=empty                 # Astro's minimal template
php artisan landing:install --template=blog                  # an official example
php artisan landing:install --template=onwidget/astrowind    # any repository
php artisan landing:install --template=https://github.com/owner/repo/tree/main/apps/site
php artisan landing:install --template=gitlab:owner/repo
php artisan landing:install --template=theme:landpack        # a theme from astro.build/themes

theme:<slug> (or the theme's astro.build/themes/details/… URL) is looked up in the catalog and installed from the repository the theme links to. Paid themes have no public repository; the installer says so and links to where to buy one, which you then install with --template=owner/repo.

Unattended

Every question has a flag. With --no-interaction the defaults are landing/, the empty template, the application's package manager and no workflow.

php artisan landing:install --no-interaction \
  --path=landing --template=basics --pm=bun \
  --add=tailwind --add=sitemap \
  --deploy=cloudflare-pages --branch=main \
  --redirect-root

Domains and routes

The landing and the application are two sites, and the recommended setup gives each its own address:

Production Local
Landing https://example.com http://localhost:4321
Application https://app.example.com php artisan serve, Herd, Valet

The application learns where the landing is from LANDING_URL (config('landing.url')). With --redirect-root (or yes to the question), the installer rewrites the application's home route to redirect there:

Route::get('/', function () {
    return config('landing.url')
        ? redirect()->away(config('landing.url'))
        : view('welcome');
})->name('home');

It is plain Laravel reading the application's own config, so it keeps working in production, where this package is not installed, and wherever LANDING_URL is not set it serves the page it served before.

To serve the landing under a path of the application's domain instead, such as example.com/lp, install with --base=/lp: Astro then builds every link and asset under /lp/, and one proxy rule on the application's domain sends /lp/ to the landing. docs/domains.md has the Nginx and Cloudflare recipes for that, for serving the build from the application's own public/, and for putting the application under paths of the landing's domain.

Running it

On Laravel 13.16 and later, composer run dev (which runs php artisan dev) starts the landing as one more process, at http://localhost:4321:

 landing php artisan landing:dev
 server  php artisan serve
 queue   php artisan queue:listen --tries=1 --timeout=0
 vite    npm run dev

On its own, or on earlier Laravel versions:

php artisan landing:dev     # astro dev
php artisan landing:build   # astro build, into landing/dist

Both install the landing's dependencies first when node_modules is missing, so a fresh clone needs nothing beyond the application's own setup. Set LANDING_DEV=false to keep the landing out of composer run dev.

Deploying it

php artisan landing:workflow cloudflare-pages

Every workflow needs the repository variable LANDING_URL, the landing's public URL. The build passes it to Astro as --site, so canonical links, Open Graph URLs, the sitemap and robots.txt point at your domain whatever the template's config says, and a build that still points at a placeholder such as https://example.com is not deployed. See docs/seo.md.

Target Repository secrets
cloudflare-pages CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID
netlify NETLIFY_AUTH_TOKEN, NETLIFY_SITE_ID
vercel VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID
github-pages none
ssh LANDING_SSH_HOST, LANDING_SSH_USER, LANDING_SSH_KEY, LANDING_SSH_PATH; optional LANDING_SSH_PORT, LANDING_SSH_KNOWN_HOSTS

The workflow is filtered to landing/**, so a change to the application never redeploys the landing. Do the reverse in your application's workflows:

on:
  push:
    branches: [main]
    paths-ignore: ['landing/**']

Deploying to two places is two files:

php artisan landing:workflow cloudflare-pages
php artisan landing:workflow ssh --file=deploy-landing-mirror

To change every workflow this package writes, publish the stubs. They are read from stubs/landing/workflows before the package's own:

php artisan vendor:publish --tag=landing-stubs

See docs/deployment.md for each target in detail.

Configuration

// config/landing.php
'path' => env('LANDING_PATH', 'landing'),
'url' => env('LANDING_URL'),                            // where visitors reach the landing
'package_manager' => env('LANDING_PACKAGE_MANAGER'),   // null: the landing's lockfile decides
'dev' => [
    'enabled' => (bool) env('LANDING_DEV', true),      // part of composer run dev
    'name' => 'landing',
],

Commands

Command What it does
landing:install Create the Astro landing and wire it into the application
landing:dev Run the Astro dev server
landing:build Build the landing into its dist/
landing:workflow Write a GitHub Actions workflow that deploys it

Working with an AI agent

If the application uses Laravel Boost, this package ships guidelines and an astro-landing-development skill. Run php artisan boost:install and tick lauroguedes/laravel-astro-landing when it asks which third-party guidelines and skills to install; the choice is saved to boost.json, so later unattended runs keep it. They tell an agent that the landing is a separate static site, which commands build and run it, how it reaches the application, and how it deploys.

Requirements

  • PHP 8.3+, Laravel 12 or 13
  • Node.js 22.12+ (or Bun) for Astro

Documentation

docs/ covers templates, domains and routes, SEO, linking the landing to the application, and each deploy target.

License

MIT. See LICENSE.md.