Framework
tempestphp/tempest-framework avatar
tempestphp/tempest-framework

Tempest PHP framework: attribute-driven routes and commands with almost no config

The PHP framework that gets out of your way

2,285 stars186 forksPHPMIT

At a glance

What is it?
tempestphp/tempest-framework is an MIT-licensed PHP framework whose controllers and console commands are plain classes tagged with attributes. The 3.x branch shipped v3.21.0 on 2026-10-29, and the repository carries a Bun workspace for its Vite plugin.
Who is it for?
Choose Tempest if you write PHP and want routes, console commands and event handlers declared as attributes on ordinary classes, with composer create-project as the entry point. Do not choose it if you were searching for the OpenStack Tempest test suite or a Python framework, because this is neither.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • tempestphp/tempest-framework2,285 ★ · +9
Star history
Repository2026-10-142026-11-07
tempestphp/tempest-framework2.3k2.3k

9 Stars in the last 24 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Routes are attributes on controller methods, not entries in a routes file

Tempest declares a route by putting an attribute on the method that serves it. In the BookController example, #[Get('/books/{book}')] sits on show(Book $book) and #[Post('/books')] sits on store(CreateBookRequest $request). There is no separate route table to keep in sync with the class.

The controller is a final class with typed parameters. The Book argument in show() is filled from the {book} segment of the URL, and store() receives a CreateBookRequest. Return values are response objects: new Ok($book) for the read, and new Redirect([self::class, 'show'], book: $book->id) for the write.

The store() body also shows the persistence style. It maps the request onto the model with map($request)->to(Book::class)->save(), so the request object, the model and the save call all stay in one expression. The design philosophy stated in the repository is that developers should write as little framework-related code as possible, and this controller is the evidence offered for it.

Console commands take dependencies through the constructor and carry middleware in the attribute

The second example in the repository is MigrateUpCommand. Its constructor takes a Console and a MigrationManager as private properties, which the container supplies. The command itself is the __invoke() method, tagged with #[ConsoleCommand] and three arguments: name: 'migrate:up', description: 'Run all new migrations', and a middleware list holding ForceMiddleware::class and CautionMiddleware::class.

That middleware list matters for anyone who has written guarded commands elsewhere. The protection for a destructive command sits in the attribute, next to the name, not in the body. A reader scanning the file sees at once which commands can be forced and which ask for caution.

The body is two lines: $this->migrationManager->up() and $this->console->success("Everything migrated"). The same class also carries an #[EventHandler] method, onMigrationMigrated(MigrationMigrated $migrationMigrated). One class therefore handles both the command and the event it triggers, and the repository's own example keeps them together.

Two install paths: a fresh project or an existing Composer project

A new project starts from the app skeleton:

code
composer create-project tempest/app <name>

An existing project adds the framework package:

code
composer require tempest/framework

The split tells you the packaging. tempest/app is the skeleton you scaffold from, and tempest/framework is the library you require. The repository itself is a monorepo, with a packages/ directory next to src/ and a monorepo-builder.php file in the root, so the framework is published as several pieces.

Both commands lead to the documentation at tempestphp.com, and the repository contains no further install steps. Nothing in the repository says which PHP version the framework needs, so check composer.json before you run either command on a server with an older PHP.

The .env.example file decides how aggressively discovery is cached

The settings in .env.example are few, and one of them changes how the framework behaves in production. DISCOVERY_CACHE accepts true, partial or false, and the shipped default is partial. INTERNAL_CACHES=true is the master switch, and setting it to false force-disables internal caches.

code
# Enable or disable discovery cache. Can be `true`, `partial` or `false`.
DISCOVERY_CACHE=partial

Because routes, commands and event handlers are found through their attributes, the framework has to scan classes to know they exist. The discovery cache is the setting that controls how much of that scan is stored. The repository does not explain what partial skips, so test a deployment with each value before choosing one.

The remaining keys are ENVIRONMENT (local, staging, production, ci, testing or other), BASE_URI, which is used for all generated URIs and defaults to http://localhost:8000, and DEBUG_LOG_PATH and SERVER_LOG_PATH, both null by default and meant for overriding the log paths.

A Bun workspace sits inside a PHP repository for the Vite plugin

The repository root holds a package.json marked private, with a workspaces entry of packages/*. This is the frontend side of the monorepo. The only workspace dependency named is vite-plugin-tempest, which is the Vite plugin the repository builds.

The scripts show the toolchain: bun for running, dprint for formatting, vitest for tests, and unbuild as a dev dependency for building. The qa script chains three steps, bun fmt, then bun run test run, then bun run build. The fmt script targets ./packages/vite-plugin-tempest/**/*.{ts,vue,json}, so the formatter touches only that package's TypeScript, Vue and JSON files.

If you contribute to the PHP side only, this does not slow you down. If you touch the Vite plugin, expect to install Bun, since every script in package.json goes through it. Other tooling files in the root, such as mago.toml, rector.php, phpstan.neon.dist, phpunit.xml.dist and phpbench.json, cover the PHP side.

Releases in the 3.x line arrived on 2026-10-22 and 2026-10-29

The repository is not archived, and its default branch is 3.x. The last push was on 2026-10-25. The recent releases are v3.19.3 and v3.20.0, both on 2026-10-22, and v3.21.0 on 2026-10-29.

Two releases in one day, a patch for the 3.19 line and a new minor, means the maintainers ship a fix and a feature release together. A new minor within a week of the previous one means the pace is fast, and anyone pinning to a minor version should expect to revisit that pin often.

The repository carries CHANGELOG.md and UPGRADING.md in the root, along with cliff.toml and .commitlintrc.json, which suggest the changelog is generated from commit messages. Read UPGRADING.md before moving between minors, since it is the only upgrade guide named in the file list.

Searching for Tempest also finds Python and OpenStack projects that have nothing to do with it

The name collides with other software. People search for Tempest framework Python and Tempest OpenStack, and neither is this project. Tempest here is written in PHP, as the Primary language field states, and it installs through Composer.

The same applies to the question of what Tempest is used for. In this repository it is used to build PHP applications: web controllers, console commands and event handlers, as the two examples show. It is not a weather term, a test suite or a Python package.

One related search asks how Tempest compares with Laravel. The repository makes no comparison, so no claim about winners belongs here. The README offers a philosophy, as little framework code as possible, and a slogan, zero config and zero overhead. Neither is a measured result. The license is MIT, the documentation is at tempestphp.com, and the README links a Discord server for questions.

Editorial conclusion

Choose Tempest if you write PHP and want routes, console commands and event handlers declared as attributes on ordinary classes, with composer create-project as the entry point. Do not choose it if you were searching for the OpenStack Tempest test suite or a Python framework, because this is neither. Before committing, read the UPGRADING.md file in the repository, since the 3.x line has already reached v3.21.0 and minor releases land weekly.

Frequently asked questions

What is Tempest used for?

Tempest is a PHP framework for building applications with controllers, console commands and event handlers declared as attributes on plain classes. The repository describes it as the PHP framework that gets out of your way.

Is Tempest the latest PHP framework?

The repository makes no claim to be the latest. Its most recent release is v3.21.0 from 2026-10-29, on the 3.x branch.

What is Tempest technology?

It is an MIT-licensed PHP framework installed through Composer, with tempest/app for new projects and tempest/framework for existing ones. Its design goal is for developers to write as little framework-related code as possible.

What are some examples of Tempest code?

The README shows a BookController with #[Get] and #[Post] routes, and a MigrateUpCommand registered with #[ConsoleCommand] under the name migrate:up.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. tempestphp/tempest-framework on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tempestphp-tempest-framework.svg)](https://hysenlabs.com/projects/tempestphp-tempest-framework)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/tempestphp-tempest-framework.svg)](https://hysenlabs.com/projects/tempestphp-tempest-framework)

Was this useful?