Circling the Beltway

Over the past few years, I’ve had a number of trips driving within or through the Washington, D.C. metro area. The Capital Beltway (Interstate 495) encircles Washington, passing through Maryland, Virginia, and a tiny corner of D.C. itself.

Map showing the Capital Beltway encircling Washington, D.C.

I-495, the Capital Beltway. (I-95 is also concurrent with the eastern half of the beltway.)

Basemap © Mapbox © OpenStreetMap (Improve this map)

The Capital Beltway is a busy road, with many complicated interchanges, local/through lanes, and tolled express lanes. I started to wonder if there was any way to circle all the way around the beltway, ending up back where I started, without changing lanes.

Problem Statement

What Is a Lane?

For this project, I define a lane as a continuous stretch of road between two painted lines (solid or dashed) that approximately parallel the direction of travel.

A two lane one-way road, with one lane labeled A and the other labeled B

A and B are both lanes.

If multiple lanes merge without needing to cross a painted line, each path counts as staying in the same lane.1 Likewise, if a lane splits into multiple lanes without needing to cross a painted line, each path counts as staying in the same lane.

Two roads. The first shows Lane C and lane D merging to Lane E, and the dashed line between C and D ends soon enough that drivers can go from C or D to E without crossing a line. The second shows Lane F splitting into Lane G and Lane H, and the dashed line between G and H begins late enough that drivers can go from F to G or H without crossing a line.

C→E, D→E, F→G, and F→H would each count as staying in the same lane.

If a lane split does require crossing a painted line, the other side of the paint is considered a new lane starting at that point. Likewise, if a lane merge does require crossing a painted line, the lane that must cross paint simply ends at that point.

Two roads. The first shows Lane J and lane K merging to Lane L, and the dashed line between J and K ends late enough that drivers can't go from K to L without crossing a line. The second shows Lane P splitting into Lane Q and Lane R, and the dashed line between Q and R begins soon enough that drivers can go from P to R without crossing a line.

J→L and P→Q would each count as staying in the same lane. Lane K ends, and R is a new lane.

Informational paint symbols (such as text, route shields, merge arrows, etc.) are not considered painted lines, and lanes continue across them.

How to Circle the Beltway

Based on Google Earth imagery and Street View data from April 2025 (the latest available at the time of this writing), I was able to find three lanes that entirely circle the Capital Beltway—two in the counterclockwise direction, and one in the clockwise direction.

I-495 Outer Loop (Counterclockwise)

The diagram below shows the Capital Beltway’s outer (counterclockwise) loop “unrolled” into a straight line. The top connects to the bottom to represent a complete circle. Start at the bottom and work your way up!

Lane continuity diagram for outer beltway, representing a visual of the instruction text below.

Minimap basemaps © Mapbox © OpenStreetMap (Improve this map)

There are two separate lane paths that will loop around the outer beltway and end up back at the same location without changing lanes (though both will end up in a different lane from where they started).

Path A

  1. In Northern Virginia, just before the E-ZPass Express Lanes split off to the left, a new lane will start as the leftmost of five lanes. Start in this new lane.
  2. Follow this lane into the E-ZPass Express Lanes.
  3. West of the Springfield Interchange, the two E-ZPass Express Lanes will merge back into the main lanes. you’ll be in the far left lane.
  4. As you approach the Springfield Interchange, this left lane will take a left exit to E-ZPass Express Lanes toward I-395 North and I-95 South.
  5. Stay in this express lane, but do not take the exits to either I-395 North or I-95 South. Instead, continue on the Express Lane toward I-95 North and I-495 East (Baltimore).
  6. This lane will eventually rejoin the beltway, and will take you into and through Maryland.
  7. You will end up back where you started in Northern Virginia just before the E-ZPass Express Lanes split, but in the rightmost lane.
  8. As the E-ZPass Express Lanes split off to the left, this rightmost lane stays in the standard I-495 lanes. Keep following this lane, and always stay on I-495 when you have the option to exit.
  9. When the E-ZPass Express Lanes rejoin west of the Springfield Interchange, you will once again be on the same road segments you were on before, but in the rightmost lane.
  10. This path leaves the beltway onto I-95 South at the Springfield Interchange.

Path B

  1. Enter the beltway from southbound I-270 Spur, in the leftmost lane. This becomes the leftmost lane of I-495.
  2. When the E-ZPass Express Lanes start in Northern Virginia, stay left into the right express lane.
  3. West of the Springfield Interchange, the two E-ZPass Express Lanes will merge back into the main lanes. you’ll be in the second lane from the left.
  4. After the Springfield Interchange, you will end up in the third lane from the left. Stay in this lane through Maryland.
  5. As you approach the split to I-270 North (Frederick), stay left onto I-495 West (Northern Virginia).
  6. When I-270 Spur merges in from your left, you’ll be back where you started, but in the right lane.
  7. Take Exit 39 toward River Road, and keep staying straight on this exit lane. The lane will eventually merge back onto the beltway after the Cabin John Parkway (and will end up in the same lane as Path A).
  8. From this onramp through the E-ZPass Express Lanes left exit, you will once again be on the same road segments you were on before, but in the rightmost lane.
  9. As the E-ZPass Express Lanes split off to the left, this rightmost lane stays in the standard I-495 lanes. Keep following this lane, and always stay on I-495 when you have the option to exit.
  10. When the E-ZPass Express Lanes rejoin west of the Springfield Interchange, you will for a third time be on the same road segments you were on before, but in the rightmost lane.
  11. This path leaves the beltway onto I-95 South at the Springfield Interchange.

I-495 Inner Loop (Clockwise)

Likewise, this diagram shows the Capital Beltway’s inner (clockwise) loop “unrolled” into a straight line. The top connects to the bottom to represent a complete circle. Start at the bottom and work your way up!

Lane continuity diagram for outer beltway, representing a visual of the instruction text below.

Minimap basemaps © Mapbox © OpenStreetMap (Improve this map)

The inner loop has a single lane path that loops back to where it started, labeled as Path C.

Path C

  1. Start on the Springfield Interchange onramp from I-95 North and I-395 South to I-495 North (Tysons Corner). Be in any of the three right lanes.
  2. After this ramp merges into the beltway, all three of these right lanes gradually merge into a single rightmost lane. Stay in this lane.
  3. As the E-ZPass Express Lanes split off to the left, this rightmost lane stays in the standard I-495 lanes. Keep following this lane, and always stay on I-495 when you have the option to exit.
  4. By the time the E-ZPass Lanes merge back into the main lanes, you’ll be in the second lane from the right. Stay in this lane into Maryland.
  5. At Exits 25B–A (U.S. Route 1), either stay on I-495 or take the exit. Both of these lanes will merge again after the U.S. Route 1 interchange and end up as the rightmost lane on I-495.
  6. At Exits 17–16, this lane will exit into the local lanes and split into two lanes. Stay in either of these two local lanes, but do not take any of the exits. These two lanes will merge after Exit 16 and rejoin the main lanes of I-495.
  7. Continue in this lane through Maryland and into the Springfield Interchange.
  8. When the I-95 North/I-395 South ramps merge onto I-495 Inner, you’ll be back where you started, but in the third lane from the left. You will continue to travel on road segments you’ve been on before all the way to the left exit for Virginia Route 267 West (Dulles Airport).
  9. This path leaves the beltway on the left exit toward Dulles.

Since this road heads towards Dulles airport, I was curious if the path might go all the way to Dulles Airport, traverse the arrival/departure loops, and return back on Virginia Route 267 East to the beltway. The lane does get to Dulles, but can only get to either the Economy Parking entrance next to the gas station, or Autopilot Drive toward rental car return. It does not loop back to the Capital Beltway.

Technical Details: How I Found the Loops

I initially thought that I could use OpenStreetMap lane data. I wrote some simple scripts, but eventually realized that while OpenStreetMap works reasonably well for getting a lane count at any given portion of well-traveled roadways, it didn’t consistently provide which lanes in one segment connected to which lanes in the next segment. Commercial lane data exists, but only at commercial licensing prices, and I couldn’t find an API that would provide it to me with per-query costs.

Because my scope was limited to a single major beltway and the ramps immediately connected to it, I decided to create my own lane connection data from aerial imagery and street view data. But first, I’d need to decide how to store it.

Directed Graph of Lanes Concept

I started by defining a road segment as a stretch of road where the lanes don’t change. From start to end, it keeps the same number of lanes in the same directions—no lanes starting, ending, merging, splitting, entering the road, or exiting the road. To identify them, each road_segment has its own unique ID number. Thus, whenever the number of lanes changes (splits, merges, entrances, exits), a new segment starts.

Each segment therefore has a consistent number of lanes along its length. Within each segment, each lane is assigned a number starting with 0 for the left lane. (For example, a three-lane one-way road has lanes 0, 1, and 2).2

A road which narrows from three lanes to two and widens back to three. It's split into three segments: the initial three lane segment (with lanes 0, 1, and 2), a middle two lane segment (with lanes 0 and 1), and an end three-lane segment (with lanes 0, 1, and 2)

Every time the number of lanes changes, a new segment starts.

In the above image, Segment 0 Lane 0 ((S0,L0)) connects to (S1,L0), which then connects to (S2,L0). (S0,L1) and (S0,L2) both connect to (S1,L1), which then connects to both (S2,L1) and (S2,L2).

This forms a directed graph where each (segment, lane) pair is a node and each connection is a directed edge.

A directed graph. Each node is a (segment, lane) pair, and they are connected as described above.

Of course, with entrances (on-ramps) and exits (off-ramps), multiple segments can connect to a single segment, and a single segment can connect to multiple segments.

With a directed graph of how each road segment’s lanes connect to other road segments’ lanes for the entire Capital Beltway, each path through the graph represents a way to traverse the beltway without changing lanes. This lets us answer the problem statement above:

Obtaining Road Geometry

Although I couldn’t use OpenStreetMap’s lane data, OpenStreetMap was still useful for the geometry (location and shape) of the road segments I needed.

First, I downloaded the latest D.C., Maryland, Virginia .osm.pbf files from Geofabrik.

To process the files, I used Osmium Tool and GDAL’s ogr2ogr. Because my primary system runs Windows and Osmium Tool doesn’t offer Windows binaries, I installed these tools into WSL:

$ sudo apt update
$ sudo apt install osmium-tool
$ sudo apt install gdal-bin

I merged the D.C., Maryland, and Virginia files into a single file:

$ osmium merge district-of-columbia-latest.osm.pbf maryland-latest.osm.pbf virginia-latest.osm.pbf -o dcmdva.pbf

I cropped the data to a longitude/latitude rectangle that encompassed the Capital Beltway plus some margin:

$ osmium extract -b -77.35,38.70,-76.75,39.05 dcmdva.pbf -o dc_bbox.pbf

I filtered the data to roads only:

$ osmium tags-filter dc_bbox.pbf -o road_segments.pbf w/highway=motorway,trunk,primary,secondary,tertiary,unclassified,residential,living_street,service,motorway_link,trunk_link,primary_link,secondary_link,tertiary_link

Finally, I converted the .pbf file to a GeoPackage file:

$ ogr2ogr -f GPKG road_segments.gpkg road_segments.pbf lines -nln roads

Under the hood, a GeoPackage file is an SQLite database. Within this database is a table of road_segments, each containing LineString geometry and indexed with a Feature ID (fid). I used the fid as my road segment ID in the directed graph.3

Building Connectors

To keep my data in one place, I decided to put the directed graph data in a non-geometry connectors table in the same GeoPackage. Each row in the table represents an edge on the directed graph, with columns for from_segment_fid, from_lane_number, to_segment_fid, and to_lane_number. The _segment_fid columns used the values from the fid (feature ID) column in the road_segments geometry table.

For example, this roadway and graph (repeated from above) would be encoded as follows:

from_segment_fid from_lane_number to_segment_fid to_lane_number
3 0 5 0
3 1 5 1
4 0 5 1
5 0 6 0
5 0 7 0
5 1 7 1

I loaded the road_segments table into QGIS to show me the location and fid of each road segment. Using Mapbox, Google Earth, and Google Street View as a reference, I worked my way around the beltway in both directions and filled out the connectors table.

Traversing the Directed Graph

Now that I had all of the lane connectors documented, I wrote a Python script to build a directed graph and look for returns to the same road segment.

Using the NetworkX package, my script loops through the connectors table and builds a directed graph.

Since this is a directed graph with edges following the direction of travel, each node’s descendants represent all of the segment-lane pairs that you can possibly travel to from that given segment-lane without changing lanes. Thus, my script loops through each node and finds any that have descendants with the same segment fid, and outputs the results as a table. It also adds attributes to the nodes, setting is_seg_loop_source for each node that has a descendant with a matching segment fid, and is_seg_loop_target for each node that is the descendant of an ancestor with a matching segment fid.

Screenshot of Windows PowerShell showing the script running. The script notes that it has created a DiGraph with 3529 nodes and 3431 edges. It then outputs a table with segment fids in the left column, and lanes in the right column. The lanes are pairs of lane numbers with a right arrow between them.

A partial sample of the output data. For each segment that can travel to itself without changing lanes, the table shows which source lane can travel to which target lane. For example, it’s possible to drive from Segment 47660 Lane 0 to Segment 47660 Lane 4 without changing lanes.

Next, my script takes all of the found matching ancestor/descendant node pairs, and uses the all_simple_paths algorithm to add an is_path flag to all nodes which are on any path between any source/target pairing. Doing this allowed me to trace how exactly I traverse the Capital Beltway to get from a segment back to itself.

Finally, the script outputs the graph and its node metadata to a GraphML file. This let me review the graph in yEd Graph Editor. I highlighted the flagged nodes in yEd, then used their segment fids to look up their geometry in QGIS, and built the lane following graphics from there.

Conclusion and Future Work

Building this graph of 3 529 nodes (road segment/lane pairs) and 3 431 edges (connectors) confirmed to me that, at least as of April 2025 imagery, it’s possible to circle the Capital Beltway in both directions without crossing any lane lines.

With more lane data, I would have liked to follow the lanes that departed the beltway to see if they’d rejoin the beltway at some point. For example, could a lane exit onto I-395 toward Washington D.C., continue on I-695 and I-295, and rejoin the beltway? Or in an even bigger circle, could a lane exit onto a highway heading away from D.C., and eventually follow some circuitous route to end up back in the D.C. metro area? Unfortunately, my solution space could conceivably involve any highway in North America, and building the lane data for the beltway alone took several hours of manual research, so it’s not practical without access to some sort of commercial lane data source.

A more reasonable future project might be to look at some other cities’ beltways. I live relatively near Cincinnati, whose I-275 beltway is one of the longest beltways in the country, and traverses three states (Ohio, Kentucky, and Indiana). I’d be able to go check my results with a quick day trip!


  1. Even if it would be technically possible for a driver to weave between the dashes of a dashed line at low speed without actually touching paint, crossing a dashed line in this manner still counts as crossing a painted line. ↩︎

  2. Road segments could possibly have lanes in two directions, either because it’s a two-way surface street or because it has reversible lanes. In that case, I would have numbered the reverse lanes with negative numbers (see Lane Numbering). In practice, I didn’t need to do this; the Capital Beltway itself and its ramps are one-way, and the reversible ramps at the Springfield Interchange to I-95 and I-395 clearly entirely left the beltway, so I didn’t include them in my lane dataset. ↩︎

  3. The road_segments table also has an osm_id column, representing the way ID in OpenStreetMap. I opted not to use it, as it would not remain unique if I ever needed to split a LineString locally. ↩︎

Tags: