Well, since you asked for “the best way” and not the most pretty or easy …
The best way is to partition your game world into axis aligned and same-sized chunks with Rect2i. Have each chunk be a region with its own source geometry.
Use the Godot 4.3 beta4 when it shows up or build from master and use the new NavigationPolygon bake rect and border size. It is PR Add NavigationPolygon `border_size` property for tile baking by smix8 · Pull Request #87961 · godotengine/godot · GitHub that added this. Set them so that each chunk bakes navigation mesh just for its Rect while also considering enough source geometry from its neighbors so that the baked navigation mesh edges can match the neighbor chunks edges in order to be merged.
Disable the edge connection margin on the navigation map, it has a super-high cost and if you setup everything correct it will not be needed at all to merge your navigation mesh edges.
For each chunk only add the relevant source geometry for the chunk and partial geometry from its neighbors. E.g. you can grow a Rect2 by the required size and check if overlaps with any of your tiles before you add them.
Keep a copy of the chunk source geometry for the static geometry that never changes. Everytime you drop dynamic stuff on the chunk duplicate this resources, add your changes to it and bake.
This altogether is the most performant way you can do runtime changes at the moment, apart from not using a TileMap as the source geometry in the first place.
if you want to base the next bake on a more optimized navigation mesh that was already baked you can iterate over the baked navigation mesh polygons and add those simpler polygons to the source geometry.
A NavigationPolygon is a mesh with indices for convex polygons. So get the polygon_count and loop over all the polygons by using get_polygon(). The array that this function returns are the indices that make the polygon. Use the indices on the vertices array to get the Vector2 positions.
If you want to optimize even further instead of adding each polygon only add the outlines of the entire navigation mesh. There is no build-in function that does this. For this you need to map the navigation mesh edges to find the outline edges, aka those with no pair. Sort them to a line with the correct winding order and add them to the source geometry. The downside of doing this is that you might have no consistency over how the mesh will look when rebaked because all the internal edge information is missing.