The routes.yaml file defines the routing configuration;
the services.yaml file configures the services of the
service container; the bundles.php file enables/
disables packages in your application.

You'll be working mostly in the config/packages/ directory. This directory
stores the configuration of every package installed in your application.
Packages (also called "bundles" in Symfony and "plugins/modules" in other
projects) add ready-to-use features to your projects.

When using Symfony Flex, which is enabled by default in
Symfony applications, packages update the bundles.php file and create new
files in config/packages/ automatically during their installation. For
example, this is the default file created by the "API Platform" package:

Splitting the configuration into lots of small files is intimidating for some
Symfony newcomers. However, you'll get used to them quickly and you rarely need
to change these files after package installation

Unlike other frameworks, Symfony doesn't impose a specific format on you to
configure your applications. Symfony lets you choose between YAML, XML and PHP
and throughout the Symfony documentation, all configuration examples will be
shown in these three formats.

There isn't any practical difference between formats. In fact, Symfony
transforms and caches all of them into PHP before running the application, so
there's not even any performance difference between them.

YAML is used by default when installing packages because it's concise and very
readable. These are the main advantages and disadvantages of each format:

YAML: simple, clean and readable, but not all IDEs support autocompletion
and validation for it. Learn the YAML syntax;

XML:autocompleted/validated by most IDEs and is parsed natively by PHP,
but sometimes it generates configuration considered too verbose. Learn the XML syntax;

PHP: very powerful and it allows you to create dynamic configuration, but the
resulting configuration is less readable than the other formats.

Sometimes the same configuration value is used in several configuration files.
Instead of repeating it, you can define it as a "parameter", which is like a
reusable configuration value. By convention, parameters are defined under the
parameters key in the config/services.yaml file:

Configuration parameters are very common in Symfony applications. Some packages
even define their own parameters (e.g. when installing the translation package,
a new locale parameter is added to the config/services.yaml file).

You have just one application, but whether you realize it or not, you need it
to behave differently at different times:

While developing, you want to log everything and expose nice debugging tools;

After deploying to production, you want that same application to be
optimized for speed and only log errors.

The files stored in config/packages/ are used by Symfony to configure the
application services. In other words, you can change
the application behavior by changing which configuration files are loaded.
That's the idea of Symfony's configuration environments.

A typical Symfony application begins with three environments: dev (for local
development), prod (for production servers) and test (for
automated tests). When running the application, Symfony loads
the configuration files in this order (the last files can override the values
set in the previous ones):

First, config/packages/framework.yaml is loaded in all environments and
it configures the framework with some options;

In the prod environment, nothing extra will be set as there is no
config/packages/prod/framework.yaml file;

In the dev environment, there is no file either (
config/packages/dev/framework.yaml does not exist).

In the test environment, the config/packages/test/framework.yaml file
is loaded to override some of the settings previously configured in
config/packages/framework.yaml.

In reality, each environment differs only somewhat from others. This means that
all environments share a large base of common configuration, which is put in
files directly in the config/packages/ directory.

See the configureContainer() method of
the Kernel class to
learn everything about the loading order of configuration files.

Symfony applications come with a file called .env located at the project
root directory. This file is used to define the value of environment variables
and it's explained in detail later in this article.

Open the .env file (or better, the .env.local file if you created one)
and edit the value of the APP_ENV variable to change the environment in
which the application runs. For example, to run the application in production:

1
2

# .env (or .env.local)APP_ENV=prod

This value is used both for the web and for the console commands. However, you
can override it for commands by setting the APP_ENV value before running them:

1
2
3
4
5

# Use the environment defined in the .env file$ php bin/console command_name
# Ignore the .env file and run this command in production$APP_ENV=prod php bin/console command_name

The default three environments provided by Symfony are enough for most projects,
but you can define your own environments too. For example, this is how you can
define a staging environment where the client can test the project before
going to production:

Create a configuration directory with the same name as the environment (in
this case, config/packages/staging/);

Add the needed configuration files in config/packages/staging/ to
define the behavior of the new environment. Symfony loads the
config/packages/*.yaml files first, so you only need to configure the
differences to those files;

Select the staging environment using the APP_ENV env var as explained
in the previous section.

Tip

It's common for environments to be similar to each other, so you can
use symbolic links between config/packages/<environment-name>/
directories to reuse the same configuration.

Using environment variables (or "env vars" for short) is a common practice to
configure options that depend on where the application is run (e.g. the database
credentials are usually different in production versus your local machine). If
the values are sensitive, you can even encrypt them as secrets.

You can reference environment variables using the special syntax
%env(ENV_VAR_NAME)%. The values of these options are resolved at runtime
(only once per request, to not impact performance).

This example shows how you could configure the database connection using an env var:

Beware that dumping the contents of the $_SERVER and $_ENV variables
or outputting the phpinfo() contents will display the values of the
environment variables, exposing sensitive information such as the database
credentials.

The values of the env vars are also exposed in the web interface of the
Symfony profiler. In practice this shouldn't be a
problem because the web profiler must never be enabled in production.

Instead of defining env vars in your shell or your web server, Symfony provides
a convenient way to define them inside a .env (with a leading dot) file
located at the root of your project.

The .env file is read and parsed on every request and its env vars are added
to the $_ENV & $_SERVER PHP variables. Any existing env vars are never
overwritten by the values defined in .env, so you can combine both.

For example, to define the DATABASE_URL env var shown earlier in this article,
you can add:

This file should be committed to your repository and (due to that fact) should
only contain "default" values that are good for local development. This file
should not contain production values.

In addition to your own env vars, this .env file also contains the env vars
defined by the third-party packages installed in your application (they are
added automatically by Symfony Flex when installing packages).

# database credentialsDB_USER=root
DB_PASS=pass # this is the secret password

Use environment variables in values by prefixing variables with $:

1
2

DB_USER=root
DB_PASS=${DB_USER}pass # include the user as a password prefix

Caution

The order is important when some env var depends on the value of other env
vars. In the above example, DB_PASS must be defined after DB_USER.
Moreover, if you define multiple .env files and put DB_PASS first,
its value will depend on the DB_USER value defined in other files
instead of the value defined in this file.

Define a default value in case the environment variable is not set:

1
2

DB_USER=DB_PASS=${DB_USER:-root}pass # results in DB_PASS=rootpass

Embed commands via $() (not supported on Windows):

1

START_TIME=$(date)

Caution

Using $() might not work depending on your shell.

Tip

As a .env file is a regular shell script, you can source it in
your own shell scripts:

This file should be ignored by git and should not be committed to your repository.
Several other .env files are available to set environment variables in just
the right situation:

.env: defines the default values of the env vars needed by the application;

.env.local: overrides the default values for all environments but only on
the machine which contains the file. This file should not be committed to the
repository and it's ignored in the test environment (because tests should
produce the same results for everyone);

.env.<environment> (e.g. .env.test): overrides env vars only for one
environment but for all machines (these files are committed);

.env.<environment>.local (e.g. .env.test.local): defines machine-specific
env var overrides only for one environment. It's similar to .env.local,
but the overrides only apply to one environment.

Real environment variables always win over env vars created by any of the
.env files.

The .env and .env.<environment> files should be committed to the
repository because they are the same for all developers and machines. However,
the env files ending in .local (.env.local and .env.<environment>.local)
should not be committed because only you will use them. In fact, the
.gitignore file that comes with Symfony prevents them from being committed.

In production, the .env files are also parsed and loaded on each request. So
the easiest way to define env vars is by deploying a .env.local file to your
production server(s) with your production values.

To improve performance, you can optionally run the dump-env command (available
in Symfony Flex 1.2 or later):

1
2

# parses ALL .env files and dumps their final values to .env.local.php$ composer dump-env prod

After running this command, Symfony will load the .env.local.php file to
get the environment variables and will not spend time parsing the .env files.

Tip

Update your deployment tools/workflow to run the dump-env command after
each deploy to improve the application performance.

Instead of defining a real environment variable or adding it to a .env file,
if the value of a variable is sensitive (e.g. an API key or a database password),
you can encrypt the value using the secrets management system.

Controllers and services can access all the configuration parameters. This
includes both the parameters defined by yourself
and the parameters created by packages/bundles. Run the following command to see
all the parameters that exist in your application:

In services and controllers not extending from AbstractController, inject
the parameters as arguments of their constructors. You must inject them
explicitly because service autowiring
doesn't work for parameters:

If you inject the same parameters over and over again, use the
services._defaults.bind option instead. The arguments defined in that option are
injected automatically whenever a service constructor or controller action
defines an argument with that exact name. For example, to inject the value of the
kernel.project_dir parameter
whenever a service/controller defines a $projectDir argument, use this:

YAML

1
2
3
4
5
6
7
8
9

# config/services.yamlservices:_defaults:bind:# pass this value to any $projectDir argument for any service# that's created in this file (including controller arguments)$projectDir:'%kernel.project_dir%'# ...

XML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

<!-- config/services.xml --><?xml version="1.0" encoding="UTF-8" ?><containerxmlns="http://symfony.com/schema/dic/services"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"><services><defaultsautowire="true"autoconfigure="true"public="false"><!-- pass this value to any $projectDir argument for any service that's created in this file (including controller arguments) --><bindkey="$projectDir">%kernel.project_dir%</bind></defaults><!-- ... --></services></container>

PHP

1
2
3
4
5
6
7
8
9
10
11
12
13

// config/services.phpuseApp\Controller\LuckyController;usePsr\Log\LoggerInterface;useSymfony\Component\DependencyInjection\Reference;$container->register(LuckyController::class)->setPublic(true)->setBindings([// pass this value to any $projectDir argument for any service// that's created in this file (including controller arguments)'$projectDir'=>'%kernel.project_dir%',]);

Finally, if some service needs access to lots of parameters, instead of
injecting each of them individually, you can inject all the application
parameters at once by type-hinting any of its constructor arguments with the
ContainerBagInterface:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// src/Service/MessageGenerator.phpnamespaceApp\Service;// ...useSymfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;classMessageGenerator{private$params;publicfunction__construct(ContainerBagInterface$params){$this->params=$params;}publicfunctionsomeMethod(){// get any container parameter from $this->params, which stores all of them$sender=$this->params->get('mailer_sender');// ...}}