serversideup/spin/spin-laravel-development

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

Develops, tests, and deploys Laravel applications using Spin and serversideup/php Docker images. Covers Docker Compose configuration, development environment setup, container commands, running Laravel tests (PHPUnit and Pest), SPIN_ENV selection and CI parity, parallel Compose environments, Laravel service configuration (databases, queues, Horizon, Reverb), server provisioning, and deployment workflows. Use when working with Spin, Docker Compose files, serversideup/php images, spin commands, running artisan test, configuring Laravel services in Docker, or deploying Laravel apps to production servers.

Install

npx vskill@latest install serversideup/spin/spin-laravel-development

SKILL.md

Spin Laravel Development

Table of contents

Safety guardrails

  • NEVER run commands that could destroy data without explicitly confirming with the user first. This includes docker system prune, docker volume rm, dropping databases, removing services, or any destructive operation.
  • Avoid spin kill — it kills all containers on the machine (not just this project) and requires interactive confirmation, which hangs in non-interactive contexts. Use spin stop or spin down for the project's stack.
  • If Spin fails to run, it is likely because Docker Desktop is not started. Check with docker info. If Docker is not running, tell the user to start Docker Desktop and offer to retry before continuing.
  • Use spin exec (running stack) or spin run (stopped stack), with -T in AI/CI/subprocess contexts — see Running commands.
  • Projects start from templates but are free to restructure. Treat the project's own compose files, Dockerfile, and .env as the source of truth for service names, versions, ports, and paths — the examples in this skill show typical template defaults, not guarantees.

Laravel Boost MCP

Spin runs PHP inside Docker, not on the host machine. Laravel Boost's MCP server needs a bridge script (spin-mcp-wait.sh) that retries until Docker is ready and filters Docker's stdout noise to preserve the JSON-RPC stdio protocol.

The required .env configuration:

env
BOOST_PHP_EXECUTABLE_PATH="./vendor/bin/spin-mcp-wait.sh ./vendor/bin/spin run -T php php"
BOOST_COMPOSER_EXECUTABLE_PATH="./vendor/bin/spin run php composer"
BOOST_NPM_EXECUTABLE_PATH="./vendor/bin/spin run node npm"

NEVER use `spin-mcp-wait.sh` to run commands. It is exclusively for MCP server startup. The script will refuse non-MCP invocations with this error:

Error: spin-mcp-wait.sh is only for starting the MCP server. Use 'spin' directly instead.

If that error appears, drop spin-mcp-wait.sh and invoke spin directly:

bash
./vendor/bin/spin exec -T php php artisan test # Correct
./vendor/bin/spin run -T php php artisan migrate # Correct
./vendor/bin/spin-mcp-wait.sh ./vendor/bin/spin run php # WRONG — never do this

How Spin works

Spin wraps Docker Compose and follows its syntax exactly. The compose-wrapping commands (up, down, stop, build, logs, ps, pull, run, exec) forward any additional flags straight to the wrapped docker compose subcommand, so every official Docker Compose option works (see COMMANDS.md for per-command exceptions).

The core pattern is Docker Compose overrides: a base docker-compose.yml is merged with an environment-specific override file. Spin sets COMPOSE_FILE=docker-compose.yml:docker-compose.$SPIN_ENV.yml automatically.

`SPIN_ENV` defaults to `dev`, so spin up is equivalent to:

bash
COMPOSE_FILE=docker-compose.yml:docker-compose.dev.yml docker compose up

Override with SPIN_ENV=testing spin up to use docker-compose.testing.yml instead.

The base file defines shared service structure. Override files add environment-specific settings. Docker merges them intelligently — override values replace or extend base values. (Image versions and service names below are illustrative — mirror the project's actual files.)

yaml
# docker-compose.yml (base — shared across all environments)
services:
traefik:
image: traefik:v3
php:
depends_on:
- traefik
yaml
# docker-compose.dev.yml (development overrides)
services:
traefik:
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./.infrastructure/conf/traefik/dev/traefik.yml:/traefik.yml:ro
php:
build:
target: development
args:
USER_ID: ${SPIN_USER_ID}
GROUP_ID: ${SPIN_GROUP_ID}
volumes:
- .:/var/www/html/
labels:
- "traefik.enable=true"
- "traefik.http.routers.laravel.rule=HostRegexp(`localhost`)"
- "traefik.http.routers.laravel.entrypoints=web"
- "traefik.http.services.laravel.loadbalancer.server.port=8080"
- "traefik.http.services.laravel.loadbalancer.server.scheme=http"
node:
image: node:24
volumes:
- .:/usr/src/app/
working_dir: /usr/src/app/
yaml
# docker-compose.prod.yml (production overrides — Docker Swarm)
services:
php:
image: ${SPIN_IMAGE_DOCKERFILE}
environment:
AUTORUN_ENABLED: "true"
SSL_MODE: full
deploy:
replicas: 1
update_config:
failure_action: rollback
order: start-first
labels:
- "traefik.http.routers.my-php-app.rule=Host(`${SPIN_APP_DOMAIN}`)"
- "traefik.http.routers.my-php-app.tls.certresolver=letsencryptresolver"

Project structure

Typical layout from the Laravel templates (individual projects may differ):

docker-compose.yml # Base (shared services)
docker-compose.dev.yml # Dev overrides (ports, volumes, build target, labels)
docker-compose.prod.yml # Prod overrides (Swarm deploy, TLS, health checks)
Dockerfile # Multi-stage: base → development → ci → deploy
.env # Read by Docker Compose AND Laravel (dual-use)
.spin.yml # Server inventory for provisioning (optional)
.infrastructure/
conf/
traefik/dev/ # Dev Traefik config + local certs (committed)
traefik/prod/ # Prod Traefik config (committed)
volume_data/
sqlite/ # SQLite data (gitignored)
redis/ # Redis data (gitignored)

The .infrastructure/ folder is flexible. conf/ stores committed configuration. volume_data/ stores gitignored persistent data for any service. This keeps everything portable — moving the project folder moves all data with it. Check the project's .gitignore to determine what is tracked.

Dockerfile pattern

Multi-stage build using serversideup/php (match the PHP version and variant to the project):

dockerfile
FROM serversideup/php:8.5-fpm-nginx-alpine AS base
# Uncomment to add PHP extensions:
# USER root
# RUN install-php-extensions bcmath gd
FROM base AS development
ARG USER_ID
ARG GROUP_ID
USER root
RUN docker-php-serversideup-set-id www-data $USER_ID:$GROUP_ID && \
docker-php-serversideup-set-file-permissions --owner $USER_ID:$GROUP_ID
USER www-data
FROM base AS ci
USER root
FROM base AS deploy
COPY --chown=www-data:www-data . /var/www/html
USER www-data

Stages: base (production image), development (matches host UID/GID via SPIN_USER_ID/SPIN_GROUP_ID), ci (root for CI pipelines), deploy (copies app code, sets permissions). The dev compose file targets the development stage via build.target.

Development workflow

This is where 90% of Spin usage happens.

Starting the environment
bash
spin up --build # Recommended: builds and starts all services (foreground)
spin up -d # Detached mode (background)

spin up runs in the foreground — open a second terminal for other commands. Press Ctrl+C to stop.

Running commands

Syntax: spin <exec|run> [-T] <service> <command> — the service argument is the service name from the project's docker-compose.yml (verify there; not every project names its services php and node).

bash
spin exec php composer install
spin exec php php artisan migrate # First "php" = service, second "php" = binary
spin run php php artisan make:model Post
spin exec node npm install
spin exec node npm run dev

`exec` vs `run`:

  • `spin exec` reuses the live container from an already-running stack. Near-instant. Default for artisan, composer, npm, and ad-hoc commands during development.
  • `spin run` creates a new container each invocation. Use when the stack is not running, or when isolated state / different env vars are needed.

The `-T` flag: Compose auto-detects TTY, so interactive terminal usage works without -T. Add -T as a defensive default when invoking from an AI agent, CI pipeline, or wrapper script — auto-detection can misfire in those contexts, causing hangs or ANSI-garbled output:

bash
./vendor/bin/spin exec -T php php artisan test # AI/CI-safe
./vendor/bin/spin exec php artisan tinker # Interactive — omit -T
Volume mounting

In development, the project directory is mounted at .:/var/www/html/, so code changes are reflected instantly — no rebuild needed for code changes.

When to rebuild

Use spin up --build when:

  • Starting a development environment (recommended as default habit)
  • After Dockerfile changes (adding PHP extensions, changing base image)
  • After modifying build-related compose settings

Code-only changes never need a rebuild — volume mounts handle it.

.env dual-use

The .env file is read by both Docker Compose (for variable substitution like ${SPIN_APP_DOMAIN}) and Laravel inside the container (since the project is volume-mounted). Example:

env
DB_HOST=mysql
DB_DATABASE=laravel
SPIN_APP_DOMAIN=laravel.dev.test
Which compose file to edit
Change typeFile
Shared service definitions (image, depends_on)docker-compose.yml
Dev-only (ports, volume mounts, build target, Traefik labels)docker-compose.dev.yml
Prod-only (deploy config, Swarm labels, named volumes, TLS)docker-compose.prod.yml
Essential commands
CommandWhat it does
spin upStart all services (docker compose up)
spin up --buildStart and rebuild
spin stopStop containers without removing them
spin downStop and remove containers
spin run <svc> <cmd>One-off command in new container
spin exec <svc> <cmd>Command in running container
spin logsView container logs
spin psList running containers
spin buildBuild images without starting

See COMMANDS.md for the complete command reference.

Running tests

Prefer the already-running dev stack — it's faster than spinning up a parallel CI stack:

bash
./vendor/bin/spin exec -T php php artisan test
./vendor/bin/spin exec -T php php artisan test --filter=ExampleTest
./vendor/bin/spin exec -T php composer test # If the project exposes a composer test script

php artisan test works for both PHPUnit and Pest.

Inspect the project's phpunit.xml before choosing a stack: if tests are self-contained (sqlite :memory:, array/sync drivers), the dev stack is plenty; otherwise it usually still works. Reach for SPIN_ENV=ci only when CI parity is explicitly needed.

See TESTING.md for the stack decision tree, the full CI-parity workflow, parallel Compose environments, and the override-network gotcha.

serversideup/php images

Choose the right variant:

VariantUse case
fpm-nginxMost Laravel apps (PHP-FPM + NGINX)
fpm-apacheApps needing .htaccess support
frankenphpLaravel Octane with FrankenPHP
cliArtisan commands, queue workers, schedulers

Tag pattern: serversideup/php:<php-version>-<variant>[-alpine] Example: serversideup/php:8.5-fpm-nginx-alpine

Key environment variables for production:

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
1,489
Repository forks
65
7-day trend score
37

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/serversideup/spin/spin-laravel-development/badge)](https://verified-skill.com/skills/serversideup/spin/spin-laravel-development)

Something wrong with this skill or its page? Tell us.