It’s managed through Git workflow. At one place we had three branches: master, alpha and release.
Master was in-progress features. By the time alpha was cut you were expected to be code complete because that was also the end of the sprint.
Alpha then went to staging servers. Bug fixes would land in master and be cherry-picked in to alpha. Eventually alpha gets promoted to release.
Emergency fixes are cherry picked directly to release.
It’s clunky and stressful, but that’s we did it at one startup I worked about 10 years ago. Everywhere uses flags.