marko/dev-server
Start your full development environment with a single command. The Dev Server package provides dev:up, dev:down, and dev:status CLI commands that orchestrate your PHP built-in server, Docker Compose services, and frontend build tools together. It auto-detects your project’s Docker Compose file and package manager, so zero configuration is required for most projects. All services are managed as background processes tracked via a PID file, letting you stop everything cleanly with dev:down.
Installation
Section titled “Installation”composer require marko/dev-serverStarting the Environment
Section titled “Starting the Environment”marko dev:up# alias: marko upThis starts all detected services:
- PHP server --- always started at
http://localhost:8000(servingpublic/) - Docker --- started if a
compose.yaml/docker-compose.ymlfile is found - Frontend --- started if
package.jsonhas adevscript (uses bun, pnpm, yarn, or npm)
By default dev:up runs in the foreground. Press Ctrl+C to stop all services.
Detached Mode
Section titled “Detached Mode”marko dev:up --detachStarts services in the background. Use dev:status and dev:down to manage them.
Checking Status
Section titled “Checking Status”marko dev:statusShows the name, PID, status (running/stopped), port, and start time for each managed process.
Stopping the Environment
Section titled “Stopping the Environment”marko dev:down# alias: marko downStops all processes started by dev:up --detach.
Changing the Port
Section titled “Changing the Port”marko dev:up --port=8080Overrides the configured port for the PHP built-in server.
Configuration
Section titled “Configuration”Publish or create config/dev.php in your application:
<?php
declare(strict_types=1);
return [ 'port' => 8000, 'detach' => false, 'docker' => true, 'frontend' => true, 'processes' => [],];Configuration Options
Section titled “Configuration Options”| Key | Type | Default | Description |
|---|---|---|---|
port | int | 8000 | Port for the PHP built-in server |
detach | bool | false | Run services in background by default |
docker | true|string|false | true | Auto-detect Docker (true), custom command (string), or disable (false) |
frontend | true|string|false | true | Auto-detect frontend (true), custom command (string), or disable (false) |
processes | array<string, string> | [] | Named custom processes to run alongside the dev environment |
The true | string | false Pattern
Section titled “The true | string | false Pattern”The docker and frontend keys accept three forms:
// Auto-detect (default): scan for compose file / package.json'docker' => true,
// Custom command: run exactly this'docker' => 'docker compose -f infrastructure/compose.yaml up -d',
// Disabled: skip entirely'docker' => false,Custom Processes
Section titled “Custom Processes”Use the processes key to run additional named processes alongside the standard services:
'processes' => [ 'tailwind' => './tailwindcss -i src/css/app.css -o public/css/app.css --watch', 'queue' => 'marko queue:work',],Each process is managed by ProcessManager --- output is prefixed with the process name (e.g. [tailwind]), and processes are tracked in the PID file when running in detached mode.
CLI Flag Overrides
Section titled “CLI Flag Overrides”Flags passed to dev:up take precedence over config file values:
| Flag | Description |
|---|---|
--port=N | Override the server port |
--detach | Run in background (detached mode) |
API Reference
Section titled “API Reference”DevUpCommand
Section titled “DevUpCommand”use Marko\Core\Attributes\Command;use Marko\Core\Command\Input;use Marko\Core\Command\Output;
#[Command(name: 'dev:up', description: 'Start the development environment', aliases: ['up'])]public function execute(Input $input, Output $output): int;DevDownCommand
Section titled “DevDownCommand”use Marko\Core\Attributes\Command;use Marko\Core\Command\Input;use Marko\Core\Command\Output;
#[Command(name: 'dev:down', description: 'Stop the development environment', aliases: ['down'])]public function execute(Input $input, Output $output): int;DevStatusCommand
Section titled “DevStatusCommand”use Marko\Core\Attributes\Command;use Marko\Core\Command\Input;use Marko\Core\Command\Output;
#[Command(name: 'dev:status', description: 'Show development environment status')]public function execute(Input $input, Output $output): int;DockerDetector
Section titled “DockerDetector”Scans the project root for Docker Compose files (compose.yaml, compose.yml, docker-compose.yaml, docker-compose.yml) and returns the appropriate up/down commands.
use Marko\DevServer\Detection\DockerDetector;
$dockerDetector = new DockerDetector(projectRoot: '/path/to/project');
/** @return array{upCommand: string, downCommand: string}|null */$dockerDetector->detect();FrontendDetector
Section titled “FrontendDetector”Checks for a package.json with a dev script and auto-detects the package manager by looking for lock files (bun, pnpm, yarn, npm --- in that order).
use Marko\DevServer\Detection\FrontendDetector;
$frontendDetector = new FrontendDetector(projectRoot: '/path/to/project');$frontendDetector->detect(); // e.g. 'bun run dev', or nullProcessManager
Section titled “ProcessManager”Manages named background processes with prefixed output streaming and signal handling for graceful shutdown.
use Marko\DevServer\Process\ProcessManager;
/** @throws DevServerException */$processManager->start(string $name, string $command): int;$processManager->stop(string $name): void;$processManager->stopAll(): void;$processManager->getPid(string $name): ?int;$processManager->getPids(): array; // array<string, int>$processManager->isRunning(string $name): bool;$processManager->runForeground(): void;PidFile
Section titled “PidFile”Persists process entries to .marko/dev.json for tracking detached processes across commands.
use Marko\DevServer\Process\PidFile;use Marko\DevServer\Process\ProcessEntry;
/** @param array<ProcessEntry> $entries */$pidFile->write(array $entries): void;
/** @return array<ProcessEntry> */$pidFile->read(): array;$pidFile->clear(): void;$pidFile->isRunning(int $pid): bool;ProcessEntry
Section titled “ProcessEntry”use Marko\DevServer\Process\ProcessEntry;
readonly class ProcessEntry{ public function __construct( public string $name, public int $pid, public string $command, public int $port, public string $startedAt, ) {}}DevServerException
Section titled “DevServerException”Extends MarkoException with contextual error messages and suggestions:
processFailedToStart(string $name, string $command)--- thrown when a process fails to start. Suggests checking the command and runningmarko dev:status.portInUse(int $port)--- thrown when the PHP server port is already in use. Suggests using--port=XXXXto pick a different port.