A $VARIABLE or ${VARIABLE} written anywhere in a Compose file is substituted by Compose itself before the file is sent to the engine. The value comes from the shell environment and from the .env file next to the Compose file. It does not come from environment: or env_file: entries, which set variables inside the container and are invisible to interpolation.
This surprises people writing a command that should evaluate at container run time, such as command: sh -c "echo $HOME". Compose substitutes the host's $HOME and the container sees the host path. Escape a literal dollar sign by doubling it: $$HOME reaches the container as $HOME.
An unset variable interpolates to an empty string with a warning rather than failing. Use ${VAR:?message} to make Compose exit with that message when the variable is missing or empty, and ${VAR:-default} to supply a fallback. The .env file is only consulted for interpolation; to put those same values inside a container, list the file under env_file.