How to Get Simple URLs When Submitting Forms in Symfony

symfony

These are my personal notes on how to simplify a get method form in Symfony

Before you read how to simplify urls on Symfony form submission, let me tell you the use case for making form urls as simple as possible. It's best suited for $_GET requests that you want to be sharable. It's much nicer to send someone to "/myapp.com?name=john" than "/myapp.com?name=john&token=3929203852398502395802398523".

The Problem

Default Symfony form submission produces URLs like this:

https://localhost:8000/date?add_days[start_date]=2026-01-20&add_days[days]=99

By default, Symfony prefixes form field names with the form's name. This is useful when you have multiple forms on the same page, but it makes URLs verbose.

The Goal

A cleaner URL without the add_days[] prefix:

https://localhost:8000/date?start_date=2026-01-20&days=99

The Solution

Instead of using $this->createForm(), inject FormFactoryInterface and use createNamed() with an empty string as the first argument:

                                                                                            
  #[Route('/date/{days?}', name: 'app_date_range_add_days')]                                       
  public function index(Request $request, FormFactoryInterface $formFactory): Response             
  {                                                                                                
      $form = $formFactory->createNamed('', AddDaysType::class);                                   
      // ...                                                                                       
  }                                                                                                
  

The empty string removes the form name prefix from all field names. You can see it in the docs here: Changing the form name

Another way to do it

AFAIK, you can also add this to your form class to do the same thing

  public function getBlockPrefix(): string
    {
        return '';
    }
  

I learned this method from AI. I'm not a fan. This removes the form name from the url every time that form is used.

I think doing it this way: $form = $formFactory->createNamed('', AddDaysType::class); is better, because if you were to use $this->createForm(AddDaysType::class) somewhere else, it would add the name spacing back. Furthermore, the method of using $formfactory->createNamed() is how they do it in the docs. The people who maintain the official docs are excellent programmers.

One more thing: turn off CSRF for shareable GET forms

CSRF tokens protect against attackers tricking a logged-in user into submitting a form that changes state. A GET form that just reads or calculates doesn't change anything, so the token adds nothing and it breaks shareable URLs.

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            // Configure your form options here
            'csrf_protection' => false
        ]);
    }
 
'csrf_protection' => true https://localhost:8000/date?start_date=2026-01-06&days=99&_token=DRYr8p53fZH6mT3NSbd9sTyL&submit=
'csrf_protection' => falsehttps://localhost:8000/date?start_date=2026-01-06&days=99&submit=