Getting Started


Requirements

Before installing Lyger, make sure your system meets the following requirements:

  • PHP 8.0+ with the ffi extension enabled
  • Composer (PHP dependency manager)
  • Rust toolchain (rustup, cargo) — only needed if you want to recompile the FFI library
  • SQLite (bundled with PHP, recommended for development)
  • Optional: PostgreSQL or MySQL for production

Installation

The fastest way to start a new Lyger project:

composer create-project betoalien/lyger my-app
cd my-app

Composer will download the framework and all dependencies in one step. Skip to Configure PHP FFI.

Option B — Git Clone

git clone https://github.com/betoalien/Lyger-PHP-Framework.git my-app
cd my-app
composer install

3. Configure PHP FFI

Lyger ships with a pre-configured php.ini. If you’re using your system PHP, make sure FFI is enabled:

; php.ini
extension=ffi
ffi.enable = 1

You can verify FFI is available:

php -r "echo extension_loaded('ffi') ? 'FFI OK' : 'FFI missing';"

4. Run the Interactive Installer

php rawr install

The installer will walk you through 4 steps:

Step Options
Architecture API Headless or Full-Stack
Frontend Vue.js, React, Svelte (Full-Stack only)
Database PostgreSQL, MySQL, SQLite
Authentication Lyger Session, JWT, None

After completing the installer:

  • Unused framework stubs are physically deleted (Zero-Bloat)
  • .env is automatically configured for your selected database
  • A .lyger_installed marker file is created

See Zero-Bloat Architecture for details on what gets removed.


Starting the Server

Starts the Rust-powered Axum HTTP server alongside the persistent PHP worker:

php rawr serve

Custom port:

php rawr serve --port=8080

The server listens on http://localhost:8000 by default.

PHP Built-in Server (Fallback)

If the Rust FFI library is not available, use PHP’s built-in server:

php rawr serve:php

This runs php -S localhost:8000 -t public behind the scenes.


Project Structure

After installation, your project will have the following structure:

my-app/
├── App/
│   ├── Controllers/          # Your application controllers
│   └── Models/               # Your application models
├── Lyger/                    # Framework core (do not edit)
├── database/
│   ├── migrations/           # Database migration files
│   └── database.sqlite       # SQLite database (if selected)
├── public/
│   └── index.php             # Application entry point
├── routes/
│   └── web.php               # Route definitions
├── storage/
│   └── queue/                # Persisted job queue files
├── libraries/                # Compiled Rust FFI libraries
├── .env                      # Environment configuration
├── php.ini                   # PHP configuration (ffi.enable=1)
├── composer.json
└── rawr                      # CLI executable

Your First Route

Open routes/web.php and add a route:

<?php

use Lyger\Routing\Route;
use Lyger\Http\Response;

Route::get('/', function () {
    return Response::json(['message' => 'Hello from Lyger!']);
});

Route::get('/hello/{name}', function ($name) {
    return Response::json(['message' => "Hello, {$name}!"]);
});

Visit http://localhost:8000/ and you should see:

{ "message": "Hello from Lyger!" }

Your First Controller

Generate a controller using the CLI:

php rawr make:controller UserController

This creates App/Controllers/UserController.php:

<?php

namespace App\Controllers;

use Lyger\Http\Request;
use Lyger\Http\Response;

class UserController
{
    public function index(Request $request): Response
    {
        return Response::json(['users' => []]);
    }

    public function show(Request $request, int $id): Response
    {
        return Response::json(['user' => ['id' => $id]]);
    }
}

Register it in routes/web.php:

use App\Controllers\UserController;

Route::get('/users', [UserController::class, 'index']);
Route::get('/users/{id}', [UserController::class, 'show']);

Your First Model

Generate a model with an accompanying migration:

php rawr make:model Post --migration

Edit the migration in database/migrations/:

public function up(): void
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->text('content')->nullable();
        $table->boolean('published')->default(false);
        $table->timestamps();
    });
}

Run migrations:

php rawr migrate

Use your model:

use App\Models\Post;

// Create
$post = Post::create(['title' => 'My First Post', 'content' => 'Hello!']);

// Read
$post = Post::find(1);
$all  = Post::all();

// Update
$post->title = 'Updated Title';
$post->save();

// Delete
$post->delete();

Environment Configuration

The .env file controls all environment-specific settings:

APP_NAME=Lyger
APP_ENV=development
APP_DEBUG=true
APP_PORT=8000

DB_CONNECTION=sqlite
DB_DATABASE=database/database.sqlite

# For PostgreSQL:
# DB_CONNECTION=pgsql
# DB_HOST=127.0.0.1
# DB_PORT=5432
# DB_DATABASE=mydb
# DB_USERNAME=user
# DB_PASSWORD=secret

Read environment variables in code:

use Lyger\Foundation\Env;

Env::load(__DIR__ . '/../.env');

$debug = Env::get('APP_DEBUG', false);
$port  = Env::get('APP_PORT', 8000);

Next Steps

  • Learn about Routing — parameters, groups, middleware
  • Explore the ORM — relationships, scopes, collections
  • Understand the Architecture — how Always-Alive and Zero-Copy work
  • Read the CLI Reference for all available rawr commands

Copyright © 2026 Lyger Framework. Distributed under the MIT License.

This site uses Just the Docs, a documentation theme for Jekyll.