Getting Started

Installation

Install Glueful with the API skeleton (or as a framework package), run the dev server, and add your first route.

Glueful has two entry points:

  1. glueful/api-skeleton for most users. This is the recommended path.
  2. glueful/framework if you are embedding the framework into an existing project.

Requirements

  • PHP 8.3+
  • Composer 2+
  • One of SQLite (default), MySQL, or PostgreSQL

Create a new project from the starter app:

composer create-project glueful/api-skeleton my-api
cd my-api

The skeleton already includes:

  • a CLI entrypoint at glueful
  • framework bootstrap in bootstrap/app.php
  • example routes in routes/api.php
  • example controller in app/Controllers/WelcomeController.php, registered in app/Providers/AppServiceProvider.php
  • default SQLite storage in storage/database/glueful.sqlite
  • three official extensions installed and enabled in config/extensions.php: glueful/users (the user store that makes login work), glueful/email-notification (the email channel for verification / password-reset mail), and glueful/media (image processing and thumbnails)

Run it

composer create-project already installs dependencies, copies .env, creates the SQLite database, and runs php glueful install --force --quiet for you (generating keys and running migrations, including the enabled extensions' tables) — so the app is ready. Start the dev server:

php glueful serve            # http://localhost:8000
php glueful serve --port=8080 --watch

Then verify the starter routes:

curl http://localhost:8000/welcome
curl http://localhost:8000/v1/status
curl http://localhost:8000/health

Using MySQL or PostgreSQL

php glueful install is engine-agnostic. Run it interactively to pick mysql, pgsql, or sqlite and enter credentials — it tests the connection first (a failed test leaves .env untouched), writes .env, and migrates:

php glueful install

Pass --quiet to reuse the existing .env without prompts (CI, scripts), or --skip-database to skip database setup entirely.

URL prefixes

Your route files are not prefixed automatically — the skeleton's routes/api.php adds its own v1 group, which is why the starter route is /v1/status. Framework and extension API routes (auth, blobs, /me, …) are mounted under the configured API prefix, /api/v1 by default:

curl -X POST http://localhost:8000/api/v1/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"[email protected]","password":"secret"}'

The prefix is controlled by API_USE_PREFIX, API_PREFIX, and API_VERSION_IN_PATH in .env; see Routing.

Add your first route

Open routes/api.php and add a route inside the existing v1 group:

<?php

use Glueful\Routing\Router;
use Glueful\Http\Response;
use App\Controllers\WelcomeController;

$router->group(['prefix' => 'v1'], function (Router $router) {
    $router->get('/status', [WelcomeController::class, 'status']);

    $router->get('/hello', function () {
        return Response::success([
            'message' => 'Hello from Glueful',
            'timestamp' => date('c'),
        ]);
    });
});

$router->get('/welcome', [WelcomeController::class, 'index']);

Test it:

curl http://localhost:8000/v1/hello

Any other routes/*.php file you create is loaded automatically too (files starting with _ are skipped, so you can keep shared partials there).

Generate new code

Glueful's current generators use the scaffold:* namespace:

php glueful scaffold:controller UserController
php glueful scaffold:model User
php glueful scaffold:dto CreateUserData

Scaffolding creates the class only. Add a route for a new controller, and register the controller in AppServiceProvider::services() (as the skeleton does for WelcomeController) so the router can resolve it — see Controllers.

Alternative: Framework Only

Install the framework package into an existing PHP project:

composer require glueful/framework

Create a minimal bootstrap:

<?php
declare(strict_types=1);

use Glueful\Framework;
use Symfony\Component\HttpFoundation\Request;

require __DIR__ . '/vendor/autoload.php';

$framework = Framework::create(__DIR__)
    ->withConfigDir(__DIR__ . '/config')
    ->withEnvironment($_ENV['APP_ENV'] ?? 'development');

$app = $framework->boot();

$request = Request::createFromGlobals();
$response = $app->handle($request);
$response->send();
$app->terminate($request, $response);

Use this path only if you already know the project structure you want. If not, use the API skeleton.

Next Steps