The framework thatgets out of your way.

Tempest embraces modern PHP and covers a wide range of features, giving you all the tools you need to focus on your code.

Zero-config code discovery

Tempest doesn't require hand-holding. Your code is scanned and everything is configured automatically: routes, view components, console commands, event handlers, middleware, migrations — everything.

final readonly class BookController
{
    #[Post('/books')]
    public function store(CreateBookRequest $request): Response
    {
        $book = map($request)->to(Book::class)->save();

        return new Redirect(uri([self::class, 'show'], book: $book->id));
    }
}
<!-- x-book.view.php-->

<article>
    <h1>{{ $book->title }}</h1>
    
    {!! $book->body !!}
</article>
final readonly class BookObserver
{
    #[EventHandler]
    public function onBookPublished(BookPublished $event): void
    {
        // …
    }
}
A refreshing new template engine

Tempest reimagines templating in PHP with a clean front-end engine, inspired by modern front-end frameworks.

Do you prefer something tried and tested? Tempest has built-in support for Blade and Twig as well.

<x-base :title="$this->seo->title">
    <ul>
        <li :foreach="$this->books as $book">
            {{ $book->title }}

            <span :if="$this->showDate($book)">
                <x-tag>
                    {{ $book->publishedAt }}
                </x-tag>
            </span>
        </li>
    </ul>
</x-base>
<!DOCTYPE html>
<html lang="en" class="h-dvh flex flex-col">
<head>
    <title :if="isset($title)">{{ $title }} — Books</title>
    <title :else>Books</title>
	
    <x-vite-tags />
    
    <x-slot name="head" />
</head>
<body class="antialiased flex flex-col grow">
    <x-slot />
    <x-slot name="scripts" />
</body>
</html>
A truly decoupled ORM

Models in Tempest embrace modern PHP and are designed to be decoupled from the database; they don't even have to persist to the database and can be mapped to any kind of data source.

final class Book
{
    #[Length(min: 1, max: 120)]
    public string $title;

    public ?Author $author = null;

    /** @var \App\Books\Chapter[] */
    public array $chapters = [];
}
$book = query(Book::class)
    ->select()
    ->where('title', 'Timeline Taxi')
    ->first();

// …

$json = map($book)->toJson();
Console applications reimagined

Thinking out of the box, Tempest's console component is a brand new approach to building console applications with PHP

final readonly class BooksCommand
{
    use HasConsole;
    
    public function __construct(
        private BookRepository $repository,
    ) {}
    
    #[ConsoleCommand]
    public function find(): void
    {
        $book = $this->search(
            'Find your book',
            $this->repository->find(...),
        );
    }

    #[ConsoleCommand(middleware: [CautionMiddleware::class])]
    public function delete(string $title, bool $verbose = false): void 
    { /* … */ }
}
And much, much more.

Configuration objects for easy autocompletion and injection, data mapping, a powerful dependency container with autowiring. Tempest is designed to be frictionless.

return new SQLiteConfig(
    path: env('DB_PATH', __DIR__ . '/../database.sqlite'),
);
./tempest static:generate

/framework/01-getting-started .... /public/framework/01-getting-started/index.html
/framework/02-the-container ........ /public/framework/02-the-container/index.html
/framework/03-controllers ............ /public/framework/03-controllers/index.html
/framework/04-views ........................ /public/framework/04-views/index.html
/framework/05-models ...................... /public/framework/05-models/index.html
// …
query('authors')
    ->insert(...$rows)
    ->execute();
final readonly class MarkdownInitializer implements Initializer
{
    public function initialize(Container $container): MarkdownConverter
    {
        $highlighter = new Highlighter(new CssTheme())
            ->addLanguage(new TempestViewLanguage());
        
        $environment = new Environment()
            ->addRenderer(Code::class, new InlineCodeBlockRenderer($highlighter));

        return new MarkdownConverter($environment);
    }
}