Directory Structure
Fast does not force a directory layout on you. It is a low-level framework, so you are free to organize a project however you like. That said, most Fast apps settle into a similar shape, and starting there will save you some decisions.
A typical project
myapp/
bootstrap.php # requires Fast's entry.php, sets up autoloading
server.php # registers routes, then calls serve()
migrate.php # runs database migrations from the CLI
.env.php # environment values, kept OUT of any static root
app/
Handlers/ # your invokable route handler classes
Models/ # your flat model classes
Middleware/ # custom middleware
views/ # embedded-PHP templates
database/
migrations/ # numbered migration files
public/
assets/ # static files served by files()
None of these names are magic. Fast does not scan app/ or auto-load your model classes for you; that is deliberate. You wire things up explicitly, which keeps the framework predictable and keeps you in control of exactly what loads.
The two entry files
Almost every project has two small files at its root.
bootstrap.php is where you require Fast and register any autoloading for your own classes:
require __DIR__ . '/framework/src/entry.php';
// Optional: a tiny PSR-4-style autoloader for your app/ namespace.
spl_autoload_register(function (string $class): void {
if (str_starts_with($class, 'App\\')) {
$path = __DIR__ . '/app/' . str_replace('\\', '/', substr($class, 4)) . '.php';
if (is_file($path)) {
require $path;
}
}
});
server.php is your actual application: it requires the bootstrap, registers everything, and calls serve().
require __DIR__ . '/bootstrap.php';
use_views(__DIR__ . '/views');
get('/', fn (): string => render('home'));
serve(port: 8080, workers: 4);
Keeping secrets safe
One rule matters a lot: never put secrets inside a directory you serve as static files. Your .env.php, your keys, and your migrations should all live outside whatever folder you hand to files(). A good habit is a dedicated public/ directory that contains only assets meant for the browser, and nothing else.
If you serve static files with
files('/assets', __DIR__ . '/public/assets'), then only the contents ofpublic/assetsare ever reachable over HTTP. Keep configuration and application code well away from it.
Autoloading your own code
Fast's autoloader only knows about the Fast\ namespace. Your model classes, handlers, and middleware need to be loadable too, either through a small spl_autoload_register like the one above, or by requiring them explicitly in your bootstrap. This is called out again in the Database section, because model classes in particular need to be loaded before you query them.
That covers the groundwork. Now let us get into the fun part: defining what your app actually does, starting with Routing.