There are, broadly speaking, two common ways to handle lots of light sources.
- Deferred techniques involve rendering some or all the information you need about your scene for lighting to render targets. For example, you may need normals, position (calculated usually from depth) and colour, each with their own render target. Then each light is drawn as a simple shape encompassing the light's range, and in the shader it uses the corresponding colour, normals, position, and its own properties from those render targets to add its influence to the rendered scene. This has been popular for a long time as it makes it easy and efficient to have a lot of lights in view, but doesn't easily support transparent objects or anti-aliasing. It also gets more difficult or expensive to support more material properties.
- Forward shading is the more traditional rendering, where an object's shader determines how it looks on screen, rather than outputting properties to a variety of render targets as in deferred shading. Different materials can handle lights differently, and transparency and anti-aliasing are straightforward. But handling an arbitrary number of lights is more difficult. Recent techniques include Forward+ and Clustered Shading, which are variations on the idea that a low-resolution texture can be prepared each frame, containing information about which lights might affect the corresponding section of the screen. Shaders can access this information by looking up the fragment's screen coordinates in a texture or two, and looping through the lights that affect that portion of the screen.
Forward+ and Clustered Shading are increasingly popular, with games like DOOM (2016) and Just Cause 3 using the latter to great effect.
I name those two games specifically, because they both have excellent resources available online detailing their lighting.