Skip to content

Using Environment Variables with Webpack Encore

Edit this page

Encore runs in Node.js, so it doesn't read Symfony's .env files and process.env in your JavaScript is unrelated to $_ENV in PHP.

To use an environment variable in your front-end code, pass it through webpack's DefinePlugin, which replaces each reference with a literal value while building.

Passing a Variable to Your JavaScript

Use configureDefinePlugin() to add your own variables. Encore already defines process.env.NODE_ENV for you:

1
2
3
4
5
6
7
8
9
// webpack.config.js

  // ...
  Encore
      .setOutputPath('public/build/')
      // ...
+     .configureDefinePlugin(options => {
+         options['process.env.SENTRY_DSN'] = JSON.stringify(process.env.SENTRY_DSN);
+     })

The key is the whole 'process.env.SENTRY_DSN' string, not a nested object. JSON.stringify() is required because DefinePlugin injects the value as raw code: without it, the value is treated as a JavaScript identifier.

The variable is then available in any file processed by Encore:

1
2
// assets/app.js
console.log(process.env.SENTRY_DSN);

Run Encore with the variable defined:

1
$ SENTRY_DSN=https://example.com/42 npm run dev

The generated file contains the literal string https://example.com/42. Nothing is looked up in the browser.

Reading Symfony's .env Files

Node.js reads .env files with the --env-file-if-exists flag, which requires Node.js 22 or later. Files that don't exist are skipped.

Symfony layers up to four files, each one overriding the previous: .env, .env.local, .env.<environment> and .env.<environment>.local. Pass each file with its own flag, in that order.

Update the scripts generated by the Encore recipe, replacing encore with node <flags> node_modules/.bin/encore:

1
2
3
4
5
6
{
    "scripts": {
        "dev": "node --env-file-if-exists=.env --env-file-if-exists=.env.local --env-file-if-exists=.env.dev --env-file-if-exists=.env.dev.local node_modules/.bin/encore dev",
        "build": "node --env-file-if-exists=.env --env-file-if-exists=.env.local --env-file-if-exists=.env.prod --env-file-if-exists=.env.prod.local node_modules/.bin/encore production --progress"
    }
}

Later files override earlier ones, which matches Symfony's own precedence: a variable defined in .env.dev.local wins over the same variable in .env.dev. Run npm run dev and npm run build as usual.

Warning

Don't use --env-file-if-exists=.env.$APP_ENV.local to make the flag environment-aware. APP_ENV is defined inside .env, which Node.js hasn't read yet when it parses its own flags, so the shell expands $APP_ENV to an empty string. The flag becomes --env-file-if-exists=.env..local and the file is skipped silently.

See the Node.js CLI docs for the full flag reference.

Values Are Frozen at Build Time

Values passed to configureDefinePlugin() are resolved when Encore runs, not when the page is served.

Warning

Each value is written into the generated file as a literal. Changing a variable in your .env file or in your shell has no effect on assets that were already built: run Encore again for the new value to be used.

This matters when deploying. If the same compiled assets are deployed to several environments, they all carry the value defined on the machine that built them.

A variable whose value changes per environment must either be built once per environment, or be passed to your JavaScript another way, such as a data- attribute rendered by Twig.

Warning

Everything passed through configureDefinePlugin() ends up in a JavaScript file served to the browser. Never pass API secrets, private keys or database credentials this way.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version