This week, we published the second beta of Symfony 8.2 so you can keep testing it before its final release. Meanwhile, we kept publishing articles about Symfony 8.2 features, such as Messenger flows, AssetMapper improvements, form improvements, validator improvements, and link sets and link templates. In addition, around 50 teams joined the Symfony AI & MCP Hackathon, and we announced that SymfonyLive Paris 2027 will take place at Espace 42 on March 26 and 27. Finally, we announced more talks for SymfonyCon Warsaw 2026.
Symfony development highlights
This week, 197 pull requests were merged (135 in code, 9 in docs, 19 in UX and 34 in AI) and 38 issues were closed (22 in code, 1 in docs, 2 in UX and 13 in AI). Excluding merges, 51 authors made additions and deletions. See details for code, docs, UX and AI.
- 4a8b773: [Validator] fix IBAN format for Côte d'Ivoire
- 5a6a0e1: [Lock] fix DoctrineDbalPostgreSqlStore refusing locks after the session is lost
- 18d4baa: [Config, Routing] fix excluded paths in XML route imports and in GlobResource ids
- 76ff247: [Mailer] don't take a word of the SMTP reply as the message id
- e53464a: [Lock] fix the PostgreSQL stores inheriting the locks of freed connections
- bfef5ab: [RateLimiter] fix CompoundLimiter accepting a hit that one limiter refused
- 3301b07: [RateLimiter] fix TokenBucketLimiter counting the wait for the next tokens from now
- 2e71575: [Security] remove accents and invisible characters from login throttling keys
- cc6f3ad: [Routing] make named groups in requirements non-capturing, like unnamed ones
- c0368e4: [Security] keep the IP limit of login throttling on successful logins
- c39a573: [Routing] fix the order of routes with host variables in compiled matchers
- 45b842f: [Routing] use the host value of variables that are both in the host and the path in compiled matchers
- c5e652b: [Security] limit login attempts of IPv6 clients by their /64 network
- d6b291d: [Security] count login attempts before checking their credentials
- f106f71: [Routing] fix compiled matchers accepting extra trailing slashes on static routes
- 87f3b51: [Messenger] fix LISTEN/NOTIFY with the DBAL pgsql driver
- e7f8e9b: [Yaml] fix block scalars losing their trailing newline after leading comments
- a37af43: [Lock] fix MongoDbStore::exists() failing before the store connected
- 76cf473: [Scheduler] fix the worker crashing when its lock expired during a long run
- e3bd776: [Lock] fix MemcachedStore locks with a TTL longer than 30 days expiring at once
- a3d008e: [Lock] fix RedisStore taking Predis error replies for a success
- 8494693: [Scheduler] fix cron triggers without a timezone taking the one of the last run after a restart
- b7c45ce: [RateLimiter] fix SlidingWindowLimiter letting reservations through faster than the limit
- c63b3f8: [Scheduler] fix ISO 8601 intervals with days, weeks or months being counted as a fixed number of seconds
- cb294ff: [Lock, Semaphore] fix RedisStore taking Predis error replies for a success
- 486d619: [Cache, HttpFoundation, Lock] fix memcached items with a TTL ending after 2038 expiring at once
- c876aaf: [Semaphore] fix RedisStore expiring semaphores too early
- dc63fa5: [Lock] fix MemcachedStore with keys that memcached rejects
- 9d9c8db: [Scheduler] fix losing or repeating runs, and truncating float intervals
- 7673304: [Cache, Messenger] fix Redis connections and Messenger transports misreading integer and boolean options
- c34fbef: [RateLimiter] fix CompoundLimiter telling to retry before all its limiters accept the hit again
- 5433996: [AssetMapper] backdate the meta file too in CachedMappedAssetFactoryTest
- a1c2a21: [RateLimiter] fix RateLimit::wait() for delays over 35 minutes on 32-bit platforms
- b82dd4e: [DependencyInjection, Routing] track the glob resource of import() so new files are detected
- 298d36c: [VarDumper] escape the content type of images in HtmlDumper
- aca4afe: [WebProfilerBundle] ignore debug headers of cross-origin responses and only link to http(s) URLs
- 2717466: [VarDumper] don't turn object property names into dump attributes and link only to http(s) URLs
- c1230af: [FrameworkBundle, HttpClient] match scopes against the URL without its userinfo
- 66ecf8c: [BrowserKit, HttpClient] don't send credentials to other origins on redirects
- 0a7df1f: [Yaml] keep spaces in plain flow mapping keys
- b8b249e: [SecurityBundle] put the listeners of a lazy firewall context back after tracing them
- 521db87: [AssetMapper] compare pre-releases in
importmap:outdated - 2e4aea9: [Workflow] escape backslashes in Graphviz HTML labels
- c937bbd: [Yaml] fix anchors, aliases and unsupported entries in flow mapping keys
- ba315cd: [Security, SecurityBundle] fix profiles listing the access decisions of previous requests
- 7f597d5: [Lock] freeze the clock in KeyTest
- 42bd99b: [AssetMapper] fix comparing 0.x and pre-release versions in
importmap:outdatedandimportmap:audit - 94ea9aa: [DoctrineBridge] use the schema editor API of Doctrine ORM in tests
- abcd744: [Validator] fix the IBAN formats sync script and synchronize formats
- 9dc27b4: [Notifier, MicrosoftTeams] fix text-only messages sent to Workflows webhooks and document their setup
- 06aad9a: [Notifier, Brevo] use the non-deprecated transactionalSMS/send endpoint
- cbef7e1: [Cache, Messenger, Notifier] fix AMQP, Memcached, Ntfy and Spot-Hit misreading DSN option values
- 9ef699b: [Cache] fix items without expiry read back as expiring in 2090
- 5ce5c9c: [HttpClient] fix testing redirects with user info on libcurl < 8.23
- 3999877: [HttpClient] document that the proxy must block private destinations behind NoPrivateNetworkHttpClient
- a3d0c2c: [TwigBridge] remove required class from expanded choice option labels
- bc829c0: [Scheduler] fix a message added to a running schedule running all its earlier slots at once
- 60d5392: [Cache] fix ChainAdapter losing the expiry of items propagated from FilesystemAdapter
- b77a5fe: [HttpClient] fix CachingHttpClient::stream() yielding a stream instead of its chunks
- d94e64f: [HttpClient] fix sending an empty body when a stream body is sent again
- 51359b5: [SecurityBundle] avoid unintended session usage with remember-me on stateless routes
- aa9b916: [FrameworkBundle] give the test session listener the same services as the real one
- 12b4394: [HttpClient] fix AmpHttpClient sending Content-Length: 0 for pipe bodies
- 6a103a4: [Cache] check cache keys even when assertions are disabled
- 0332802: [HttpClient] don't report the user info of URLs
- 734134a: [HttpClient] fix parsing an SSE event with an empty type or an empty first data line
- 907a924: [Mailer, AhaSend] call api.ahasend.com for the API
- 8eacd67: [Messenger] fix the Redis keepalive check comparing milliseconds with seconds
- 03dec0e: [TypeInfo] fix Type::fromValue() for string keys that name a callable
- 197183f: [JsonStreamer] stop expanding generic types that get too long
- 75b0d15: [TypeInfo] fix Type::fromValue() for generators that yield boolean keys
- 078c618: [PropertyInfo, TypeInfo] don't throw on docblock types with invalid array keys
- 7276e0a: [Messenger] fix the Redis transport ignoring the cluster option
- de91878: [Mailer, AhaSend] use the Message-ID header as the id of messages sent over SMTP
- f72e124: [Cache, Messenger] fix Redis connections and the Beanstalkd transport reading invalid option values as 0 or false
- 41ec0b2: [Messenger] close the CloseableTransportInterfaces when the worker stops
- 6eb1d58: [Mailer] require TLS when bridges connect with STARTTLS
- 8553967: [Mailer, Postal] keep the display names of the addresses
- 85fbf72: [Notifier] fix the Ntfy and Spot-Hit transports misreading secureHttp and smslongnbr
- b3cd194: [Mailer, AhaSend] do not send Bcc addresses as a header
- 7b67216: [HttpClient] fix CachingHttpClient failing to stream no-store requests together with other requests
- 5c8a274: [Mailer, Sweego] do not send Bcc addresses as a header
- 9b8be99: [Runtime] reset the memory peak between FrankenPHP worker requests
- f681e28: [HttpFoundation] parse HTTP dates as RFC 9110 says
- 745fc2c: [HttpClient] fix taking invalid HTTP dates for valid ones
- ddb61be: [HttpClient] read Retry-After dates as HTTP-dates in RetryableHttpClient
- 4ac4644: [HttpClient] fix CurlHttpClient resending request bodies on redirects
- 46e7a21: [DoctrineBridge] fix UniqueEntity default error path when fields is a mapping
- 19af737: [Cache, FrameworkBundle] fix async recomputation for chains and decorated pools
- df8a5c4: [HttpClient] don't send an event source request again when its method is not idempotent
- 51c87cf: [FrameworkBundle] use the share directory for file sessions
- 51d218e: [HttpKernel] accept JSON and XML media type variants in #[MapRequestPayload]
- 039017e: [HttpClient] let the test suite run on another port so that several runs can work in parallel
- 452bd87: [Tui] don't carry a style that ends where a line wraps over to the next line
- 9b27054: [Tui] close a hyperlink at the end of a wrapped line and reopen it on the next one
- 4a64e00: [Tui] don't leave a style open at the end of a wrapped line
- 7f525ae: [HttpKernel] normalize percent-encoding in the default #[RateLimit] key
- 90e5d51: [Messenger] keep alive the fetched messages that wait for their turn
- ba5f74a: [Semaphore] fix LockStore::save() trusting slots that were lost on the backend
- f335ac5: [ObjectMapper] fix unmapped source properties being read needlessly
- 0e8064a: [SecurityBundle] default the audience of the oidc and oauth2 token handlers to the resource of resource_metadata
- bf55d0f: [Messenger] fix replacing a parallel worker that reached its memory limit
- a22953d: [Messenger] reset services after a failed parallel dispatch
- 330e588: [Messenger] fix the Redis transport losing pending messages after a failed read
- f54a154: [TwigBridge] check the domain and the position of trans_default_domain ... for _self and require Twig 3.29
- 5eec419: [AssetMapper] resolve the env vars of asset_mapper.server when the container is compiled
- 8c4847a: [Config] tell in config references when env vars are resolved at compile time
- f431250: [Messenger] fix RedisReceiver losing the rest of a batch when rejecting an entry without data fails
- 6fc56d2: [Messenger] fix parallel workers crashing on errors that cannot be serialized
- 5797f06: [Messenger] fix parallel workers crashing or hanging on errors in their child processes
- a152472: [Config] compare resource freshness with cache build start
- 923a931: [Lock] do not query the store when the key has no state
- 9f60a31: [Mailer, AhaSend] take the Message-ID from message_id_header, without angle brackets
- 7e4e2ca: [Yaml] encode schema paths in file URIs
- 7a95884: [Mailer] require TLS when more bridges connect with STARTTLS
- d8936ad: [KeyManagement] use the schema editor API of Doctrine ORM in tests
- 43de4ec: [Mailer, Notifier] deprecate non-boolean verify_peer and auto_tls SMTP options, and validate the poll options of Instagram and Threads
- f40f2ca: [Messenger] close AMQP connections when the transport closes
- 4ce6592: [RateLimiter] fix TokenBucketLimiter counting the reset time from now
- bbad402: [HttpFoundation, RateLimiter] fix combined limiters reporting a reset time before all their limiters are back to full capacity
- ae0a0c1: [DependencyInjection] fix attribute configurator phpdoc rejecting narrowed reflectors
- 5791e9b: [JsonSchema] fix the schema of properties that have a serialized path
- e785b64: [JsonSchema] use object keywords for Count, NotBlank and Choice on arrays described as objects
- c1eea8f: [JsonSchema] skip values that JSON cannot encode
- 420598f: [Routing] reject route parameters named or mapped to "_firewall" and "_firewall_context"
- dc43801: [Security] refuse DPoP-bound access tokens presented as bearer tokens
- 8edd114: [HttpKernel] warm property info for mapped controller arguments
- 9f8a21c: [PropertyInfo, Serializer, Validator] warm classes from tagged providers
- 979969d: declare bundle options that resolve at compile time
Symfony UX development highlights
- 8bfc75e: [LiveComponent, TwigComponent] keep the mergeable values passed to a component
- e8b3ab1: [Css] skip escaping the classes of css() when they need none
- 2c57e6c: [Css] let a Twig component caller override the classes of css()
- 0049078: [Css] cache the classes of the css() hashes only known at runtime
- 733bf2d: [TwigComponent] fix the pre-lexer ending an expression at the }} of a nested hash
- 940ffe1: [Css] add the cva() function
Symfony AI development highlights
- 2ac58dd: [Platform, Anthropic] add a prompt-caching breakpoint on the previous user message
- df8a079: [Platform, OpenAI] read the rate limit reset durations OpenAI sends
- 8da1d7f: [MCP Bundle] add http.max_body_bytes option to configure the request body size limit
- d6b1970: [Agent] answer the call of a tool that returns nothing
- 81412cf: [Platform] describe a Regex constraint with its own pattern
- d03d271: [Mate] recognize .claude/CLAUDE.md like a root CLAUDE.md
- d293883: [Mate] point agents to Mate first for facts about past requests
- e2b5e84: [Mate] stop creating a CLAUDE.md
- 20c8b8a: [Platform, Ollama] read the cached prompt tokens
- 5a1fb34: [Platform, Mistral] read the remaining tokens instead of the limit
- af432d8: [Store, Redis] return every document a query finds
- 69e7de0: [Platform, Gemini] read the retry delay Gemini sends with a rate limit
- 36340a3: [Mate, Symfony] add an HttpClient profiler formatter
- d04254f: [Mate, Monolog] do not hide compressed log rotations from the log tools
- ef46461: [Mate] wire the log tools into the profiler workflow and back
- 8046c4f: [Mate] turn the profiler skill's reading order into an investigation loop
- 648de75: [Mate, Symfony] say when symfony-profiler-list returned only a page
- 39d82a3: [Mate, Monolog] find the context of a log line whose strings hold escaped quotes
- 1dd634c: [Mate] link awesome-mate from the README
- 1288292: [AI Bundle, Agent, MCP Bundle] move to mcp/sdk 0.10 and bind sessions to the user
- 41c6126: [Store, Pinecone] move to API version 2026-07
- 809af8b: [AI Bundle] describe the list of tools of an agent in the config schema
- c0cb436: [Agent] fix Redis message store staying in WATCH and overwriting keys it cannot read
- 2b39690: [AI Bundle, Store] accept a DSN in the PDO-based stores
- ca2c926: Feature/execution cancellation reason
- 7bece85: [Store] add RegexSplitTransformer for pattern-based document splitting
- 2f5804b: [AI Bundle] keep the tool call listeners working without the security or validator service
- 9b41fdc: [Store, SurrealDb] wait for HNSW compaction in integration test
- a5d0257: [AI Bundle] show configured components and their calls in the profiler panel
- c4cb5da: [Store] read the same option for the number of results in all stores
- 8fa3e36: [AI Bundle, Agent] register ModelOverrideInputProcessor for every agent
Newest issues and pull requests
- [RFC] Configure more component services with PHP attributes
- [RFC][Cache] Serve the old value while one request refreshes it (stale-while-revalidate past the TTL, and a soft tag invalidation)
- [RFC][Cache][Lock] Stampede protection that spans the fleet, with the waiters woken by a message
- [RFC][Cache] A tag-aware Redis adapter whose invalidation does not walk the matches
- [Feature] Native AMQP Messenger Transport
Symfony Jobs
These are some of the most recent Symfony job offers:
-
Backend Symfony Developer at Edflex
Full-time - €45,000 – €55,000 / year
France Remote + part-time onsite (Nantes, Paris, France)
View details -
Symfony Developer at Bas Software
Full-time - €4,000 – €5,000 / month
Netherlands Remote + part-time onsite (Eindhoven, Netherlands)
View details -
Backend Symfony Developer at UpcoMinds
Full-time - €2,800 – €3,200 / month
Greece Remote + part-time onsite (Athens, Greece)
View details -
Backend Symfony Developer at MyUnisoft
Full-time - €45,000 – €50,000 / year
France Remote + part-time onsite (Montigny-le-Bretonneux, France)
View details -
Symfony Developer at Bas Software
Full-time - €5,500 – €6,500 / month
Netherlands Remote + part-time onsite (Eindhoven, Netherlands)
View details
You can publish a Symfony job offer for free on symfony.com.
SymfonyCasts Updates
SymfonyCasts is the official way to learn Symfony. Select a track for a guided path through 100+ video tutorial courses about Symfony, PHP and JavaScript.
This week, SymfonyCasts published the following updates:
They talked about us
- How Symfony UX CSS Works Under the Hood
- Let readers read and admins write on an MCP server, with Symfony
- Protect your Symfony login against brute force with login_throttling
- Draft by Agent, Approve by Human: A Publishing API and MCP Server for Symfony 8.1
- Put your notes behind an MCP server without writing a login
- Jane 8: modern PHP models, Symfony HttpClient and lazy API calls
- Stop Paying for Idle Tenants: Database-per-Tenant Symfony 8.1 on One Shared Deployment
- Secret Santa in 2026: exclusions, Slack Connect, and a fresh coat of paint
- New in EasyAdmin 5.10
- Protéger le login Symfony contre la force brute avec login_throttling
- Secret Santa 2026 : Slack Connect, exclusions et un coup de neuf
- Нововведения Symfony 8.2: режим sudo, ускорение Messenger и поддержка PGP/MIME
Call to Action
- Follow Symfony on X, on Mastodon, on Bluesky and on Threads and share this article.
- Subscribe to the Symfony blog RSS and never miss a Symfony story again.