- Docker + VS Code Dev Containers or a local PHP 8.5 + Composer environment
- mise (manages Bun, gh, Caddy, Composer, Dagger, and task running)
Create a .env file in the project root (gitignored) before the first run:
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET= # generated by `mise setup`, or put 32 hex chars here
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
DATABASE_URL="postgresql://symfony:secret@localhost:5432/symfony?serverVersion=18&charset=utf8"
###< doctrine/doctrine-bundle ###
###> symfony/mailer ###
MAILER_DSN=smtp://localhost:1025 # Mailpit (web UI on localhost:8025)
###< symfony/mailer ###
###> symfony/messenger ###
MESSENGER_TRANSPORT_DSN=sync://
###< symfony/messenger ###
###> symfony/lock ###
LOCK_DSN=flock
###< symfony/lock ###
###> symfony/routing ###
DEFAULT_URI=http://localhost:8000
###< symfony/routing ###
###> nelmio/cors-bundle ###
CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'
###< nelmio/cors-bundle ###
###> symfony/debug-bundle ###
VAR_DUMPER_SERVER=127.0.0.1:9912
###< symfony/debug-bundle ###
###> lexik/jwt-authentication-bundle ###
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=change-me
###< lexik/jwt-authentication-bundle ###Notes:
TRUSTED_PROXIESandTEST_TOKENare not needed — they are wrapped inenv(default::…)and, in the devcontainer,DEFAULT_URI/TRUSTED_PROXIESare also injected by the.mise.tomltemplates (see Services & Devcontainer).- After setting
JWT_PASSPHRASE, generate the keypair once:php bin/console lexik:jwt:generate-keypair(the.pemfiles are gitignored). If you change the passphrase later, regenerate with--overwrite. - Local overrides belong in
.env.local(gitignored, wins over.env).
Open the project in its devcontainer, then run:
mise run setupThis single command:
- Installs Composer dependencies (
vendor/) - Installs Bun (Node) dependencies (
node_modules/) - Generates Symfony secrets keys for the
devenvironment - Creates the database and runs all migrations
To set up for production secrets instead:
mise run setup prodmise run devThis starts three concurrent mise tasks (.mise/tasks/dev/):
| Task | Command | Purpose |
|---|---|---|
dev:php-fpm |
php-fpm |
PHP FastCGI process manager |
dev:caddy |
caddy |
Reverse proxy + static file server on http://localhost:8000 |
dev:scheduler |
messenger:consume scheduler_default |
Symfony Scheduler worker |
When the async Messenger transport is enabled (see config/packages/messenger.yaml),
add a dev:worker task alongside these that runs messenger:consume async.
Next: seed some demo data with mise run db:seed (see Database)
and explore the Application Guide.