A framework externalizes configuration (base URL, browser, timeouts, environment, credentials) into properties/YAML/JSON files or environment variables, read through a ConfigReader, so the same tests run anywhere without code changes.
Hard-coding URLs, browsers, or timeouts makes tests un-portable. Instead, a config.properties (or per-env dev.properties/prod.properties) holds these values, loaded once by a ConfigReader utility; tests/pages ask ConfigReader.get('baseUrl'). Environment selection (which file) comes from a system property or env variable (-Denv=staging), so CI runs the same suite against any environment. SECRETS (passwords, tokens) should come from environment variables or a vault, never committed. Good config design supports cross-browser (browser property), cross-environment, and CI overrides. Scattered hard-coded values are a top maintainability smell.
ConfigReader.get('baseUrl') returns the URL for the active environment chosen by -Denv=staging, so the identical suite tests dev, staging, and prod by changing one flag in CI.
How do you design the framework so the same tests run against dev, staging, and prod with different URLs and credentials?