Phoenix App CORS Configuration Issue with Deployment

I’m encountering a CORS configuration issue in my Phoenix app during deployment due to a mismatch between compile-time and runtime configurations.

Current Setup

In endpoint.ex, before MyApp.Router, I have:

plug CORSPlug, origin: Application.compile_env(:my_app, :cors_origin)

In config.exs (for dev and test environments):

config :my_app,
  cors_origins: System.get_env("CORS_ORIGINS", "*") |> String.split(",")

In runtime.exs:

config :my_app,
  cors_origins: System.fetch_env!("CORS_ORIGINS") |> String.split(",")

The Issue

When deploying to production (using Fly.io), I encounter this error:

ERROR! the application :my_app has a different value set for key :cors_origins during runtime compared to compile time. Since this application environment entry was marked as compile time, this difference can lead to unexpected behavior:
* Compile time value was not set
* Runtime value was set to: ["http://localhost:5173"]

If I change endpoint.ex to use Application.get_env/2:

plug CORSPlug, origin: Application.get_env(:my_app, :cors_origin)

the app deploys successfully, but I see a warning that get_env/2 is discouraged in this context.

I’ve been troubleshooting this for about eight hours and could use some guidance. Am I overlooking something? Any help would be greatly appreciated!

Hi, you can control check_origin via config files (runtime.exs, config.exs, dev.exs and test.exs:

config :your_app, YourAppWeb.Endpoint,
check_origin: "your_value"

and control prod, dev, and test env as you wish, no need to edit endpoint.ex file where you can only set values during compilation phase.

1 Like

If anyone encounters the same issue in the future, here’s how I resolved it:

I moved the environment variable fetching logic to a helper module, which fixed the problem.

plug CORSPlug, origin: &MyAppWeb.Config.cors_origins/1

Here’s the helper module:

defmodule MyAppWeb.Config do
  def cors_origins, do: Application.get_env(:my_app, :cors_origins)
end

Note: Ensure you use the capture operator (&) when calling the function in the plug. Calling it without the capture operator will not work—I made this mistake and spent an entire day debugging it.

I hope this helps anyone facing a similar issue!

1 Like

Thank you for posting the solution.

Any insight on why you didn’t use Application.compile_env instead? Do you expect modification of the application’s configuration at runtime?

I opted not to use Application.compile_env because I needed the flexibility to update the origins dynamically without requiring a recompilation.

1 Like

Thought so, thanks for elaborating.

1 Like