boatware / symfony-starter
A production-ready Symfony 8 starter kit — auth, admin, async messaging, Tailwind CSS, FrankenPHP and Bun.
Package info
codeberg.org/boatware3/symfony-starter
Type:project
pkg:composer/boatware/symfony-starter
Requires
- php: >=8.4
- ext-ctype: *
- ext-fileinfo: *
- ext-gd: *
- ext-iconv: *
- ext-yaml: *
- ext-zip: *
- doctrine/doctrine-bundle: ^3.2.2
- doctrine/doctrine-fixtures-bundle: ^4.3.1
- doctrine/doctrine-migrations-bundle: ^4.0
- doctrine/orm: ^3.6.2
- league/commonmark: ^2.9
- nyholm/psr7: ^1.8.2
- phpdocumentor/reflection-docblock: ^5.6.6
- phpstan/phpdoc-parser: ^2.3.2
- symfony/asset: 8.0.*
- symfony/console: 8.0.*
- symfony/doctrine-messenger: 8.0.*
- symfony/dotenv: 8.0.*
- symfony/expression-language: 8.0.*
- symfony/flex: ^2.10
- symfony/form: 8.0.*
- symfony/framework-bundle: 8.0.*
- symfony/http-client: 8.0.*
- symfony/intl: 8.0.*
- symfony/mailer: 8.0.*
- symfony/messenger: 8.0.*
- symfony/mime: 8.0.*
- symfony/monolog-bundle: ^3.0|^4.0.1
- symfony/notifier: 8.0.*
- symfony/process: 8.0.*
- symfony/property-access: 8.0.*
- symfony/property-info: 8.0.*
- symfony/rate-limiter: 8.0.*
- symfony/requirements-checker: ^2.0.3
- symfony/runtime: 8.0.*
- symfony/security-bundle: 8.0.*
- symfony/serializer: 8.0.*
- symfony/stimulus-bundle: ^2.32
- symfony/string: 8.0.*
- symfony/translation: 8.0.*
- symfony/twig-bundle: 8.0.*
- symfony/uid: 8.0.*
- symfony/ux-autocomplete: ^2.32
- symfony/ux-turbo: ^2.32
- symfony/validator: 8.0.*
- symfony/web-link: 8.0.*
- symfony/webpack-encore-bundle: ^2.4
- symfony/yaml: 8.0.*
- twig/extra-bundle: ^3.23
- twig/markdown-extra: ^3.23
- twig/twig: ^3.23
Requires (Dev)
- dama/doctrine-test-bundle: ^8.6
- friendsofphp/php-cs-fixer: ^3.94.2
- pestphp/pest: ^4.4.2
- phpstan/phpstan: ^2.1.40
- phpunit/phpunit: ^12.5.12
- symfony/browser-kit: 8.0.*
- symfony/css-selector: 8.0.*
- symfony/debug-bundle: 8.0.*
- symfony/maker-bundle: ^1.66
- symfony/stopwatch: 8.0.*
- symfony/web-profiler-bundle: 8.0.*
- vimeo/psalm: ^6.15.1
- zenstruck/foundry: ^2.9.2
Conflicts
This package is not auto-updated.
Last update: 2026-03-16 23:17:52 UTC
README
A production-ready Symfony 8 starter kit. Everything you need to ship a real application — authentication, admin panel, async messaging, and modern frontend tooling — pre-wired and ready for your domain.
composer create-project boatware/symfony-starter my-app
cd my-app && make setup
open http://localhost:9161
What's included
| Feature | Details |
|---|---|
| Authentication | Registration · Email verification · Login · Password reset & change — CSRF-protected, rate-limited |
| Admin panel | User management · Audit log · Disk space monitor · Async mail tester |
| Settings | Per-user account settings with secure verification-token flows for email & password changes |
| Async messaging | Symfony Messenger with Doctrine transport (no extra broker needed) |
| Templated HTML emails (EN + DE) via Symfony Mailer; caught locally by Mailpit | |
| i18n | English and German out of the box; add more locales in minutes |
| Frontend | Tailwind CSS 4 · Stimulus · Turbo · Webpack Encore · Bun |
| Code quality | PHPStan (max) · Psalm · PHP-CS-Fixer · PHPUnit / Pest |
| CI/CD | GitHub Actions · GitLab CI · Jenkinsfile — all ready to go |
| Runtime | FrankenPHP (replaces nginx + php-fpm) · PostgreSQL 16 |
Quick start
Prerequisites
1. Create the project
composer create-project boatware/symfony-starter my-app
cd my-app
composer create-projectautomatically copies.env.dist→.envand generates a freshAPP_SECRET.
2. Review .env
Open .env and adjust anything that needs to change (database name, port, mailer settings, …). Defaults work out of the box for local development.
3. Start the stack
make setup
This builds the Docker image, installs PHP and JS dependencies, builds frontend assets, runs database migrations, and seeds the database.
4. Open the app
http://localhost:9161
| URL | Service |
|---|---|
http://localhost:9161 | Application |
http://localhost:8025 | Mailpit (caught emails) |
http://localhost:8081 | Adminer (database UI) |
5. Log in
| Password | Role | |
|---|---|---|
admin@example.com | admin | Admin |
user@example.com | user | User |
Change these passwords immediately on any non-local environment.
Development
Container commands
All PHP commands run inside the php container:
docker compose exec php bin/console <command>
docker compose exec php composer <command>
docker compose exec php bun run <script>
Make targets
make setup # First-time setup
make start # Start containers
make stop # Stop containers
make destroy # Remove containers (keep volumes)
make destroy-volumes # Remove containers AND data volumes
make lint # PHP syntax check
make phpcs # Fix code style
make phpcs-dry # Check code style (dry run)
make phpstan # Static analysis (PHPStan)
make psalm # Static analysis (Psalm)
make test # Run full test suite
make qa # All checks + tests
make cache # Clear Symfony cache
make auto-migrate # Generate + run DB migration
make reset-database # Drop, recreate, migrate, seed
make generate-secret # Regenerate APP_SECRET in .env
make start-messenger # Start async worker manually
Asset pipeline
Assets are compiled with Webpack Encore, run by Bun (instead of npm):
docker compose exec php bun run dev # Development build
docker compose exec php bun run watch # Watch mode
docker compose exec php bun run build # Production build
Database
The default database URL points to the PostgreSQL container.
For a local connection (e.g. from a GUI client), check the DB_PORT in .env (default 5432).
Sending emails
In development all emails are intercepted by Mailpit at http://localhost:8025. No emails leave your machine.
Architecture
Directory structure
src/
Command/ CLI commands
Controller/ HTTP layer — all extend BaseController
DataFixtures/ Foundry factories + stories (groups: dev, test)
Entity/ Doctrine ORM entities (final, UUID PKs)
Enum/ PHP 8.1 enums (Role, LogLevel)
EventSubscriber/ Locale detection, session debug, preview reset
Exception/ EntityMismatchException
Form/ FormTypes + DTOs
Message/ Messenger message classes (async/sync)
MessageHandler/ Corresponding handlers
Monolog/ DoctrineLogHandler (writes to DB)
Pagination/ Generic pagination helper
PHPStan/ Custom PHPStan rules
Repository/ Data access layer
Security/ UserChecker
Service/ Business logic (Mailer, ContentRenderer, DiskSpace, Validators)
Twig/ AppExtension
Key conventions
Entities — final, implement EntityInterface (toArray()), UUID primary key via PHP 8.4 asymmetric visibility (public private(set) Uuid $id).
Repositories — implement RepositoryInterface, expose save() / delete() (throw EntityMismatchException on wrong type).
Controllers — extend BaseController, use #[Route] attributes, #[IsGranted] for auth, #[CurrentUser] for injection.
Forms — edit flows use DTOs; Service/DTO/ services handle entity↔DTO conversion.
Translations — translations/messages+intl-icu.{en,de}.yml for application messages, security+intl-icu.{en,de}.yml for authentication.
Content pages — static Markdown files in content/{locale}/ rendered via ContentRenderer (supports front-matter for template selection).
Custom PHPStan rules
Three rules are enforced in src/PHPStan/Rules/:
| Rule | Enforces |
|---|---|
ControllerExtendsBaseControllerRule | All controllers must extend BaseController |
EntityMustBeFinalRule | All entities must be final |
RepositoryMustImplementInterfaceRule | All repositories must implement RepositoryInterface |
Configuration
Environment variables
| Variable | Default | Description |
|---|---|---|
APP_ENV | dev | dev / prod / test |
APP_SECRET | (generated) | Symfony secret — generated on create-project |
APPLICATION_PORT | 9161 | Host port the app listens on |
DATABASE_URL | (see .env.dist) | PostgreSQL connection string |
MESSENGER_TRANSPORT_DSN | doctrine://default?... | Messenger transport |
MAILER_DSN | smtp://mailer:1025 | Mailer transport |
MAILER_FROM_NAME | Symfony Starter | Sender name |
MAILER_FROM_ADDRESS | noreply@example.com | Sender address |
TIMEZONE | UTC | App timezone |
IS_PREVIEW_SYSTEM | 0 | Show preview reset banner |
Changing the app name
Update app.name in translations/messages+intl-icu.en.yml (and .de.yml). Also update MAILER_FROM_NAME in .env.
Adding locales
- Add the locale to
app.localesinconfig/services.yaml - Create
translations/messages+intl-icu.{locale}.yml - Create
translations/security+intl-icu.{locale}.yml - Create
content/{locale}/withimprint.mdandprivacy.md - Add email templates under
templates/emails/{locale}/
Testing
make test # Full suite (prepare-test + pest)
Tests are split by type:
| Path | Type |
|---|---|
tests/Unit/ | Isolated, no DB |
tests/Integration/ | Kernel-booted, wrapped in transactions (DAMA) |
tests/Controller/ | WebTestCase HTTP tests |
tests/Security/ | CSRF, rate-limiting, token security |
tests/Browser/ | Browser simulation |
Deployment
Production with Docker
make restart-prod
This rebuilds the production image, installs prod-only PHP/JS deps, runs migrations, and warms the cache.
Environment
Copy .env.dist to .env on the server and set:
APP_ENV=prod
APP_SECRET=<long-random-string>
DATABASE_URL=postgresql://...
MAILER_DSN=smtp://your-smtp-server
FrankenPHP HTTPS
To enable automatic TLS, change SERVER_NAME in your environment:
# Single domain
SERVER_NAME=example.com
# With www redirect
SERVER_NAME=example.com, www.example.com
FrankenPHP (via Caddy) will obtain and renew Let's Encrypt certificates automatically.
Contributing
See CONTRIBUTING.md.
License
MIT — see LICENSE.md.