How to convert cuboid to mesh efficiently

cuboids = Table[Cuboid @@ (pts = RandomReal[100, {2, 3}]), {i, 10000}];

cuboids /. 
   Cuboid[{x1_, y1_, z1_}, {x2_, y2_, z2_}] :> 
    MeshRegion[{{x1, y1, z1}, {x2, y1, z1}, {x2, y2, z1}, {x1, y2, z1},
      {x1, y1, z2}, {x2, y1, z2}, {x2, y2, z2}, {x1, y2, z2}},
        {Polygon[{{4, 3, 2, 1}, {1, 2, 6, 5}, {2, 3, 7, 6},
          {3, 4, 8, 7}, {4, 1, 5, 8}, {5, 6, 7, 8}}]}]; // AbsoluteTiming

{0.330509, Null}

Replace MeshRegion with BoundaryMeshRegion

{16.3816, Null}


You can use the OpenCascadeLink (that ships with Wolfram Language since version 12.1 or from GitHub) for this:

Needs["OpenCascadeLink`"]
cuboids = 
  Table[Cuboid @@ (pts = RandomReal[100, {2, 3}]), {i, 10000}];

AbsoluteTiming[
 r = BoundaryDiscretizeGraphics[#, MaxCellMeasure -> \[Infinity]] & /@
     cuboids;]

{36.422, Null}

AbsoluteTiming[
 s = OpenCascadeShape /@ cuboids;
 bmeshs = OpenCascadeShapeSurfaceMeshToBoundaryMesh /@ s;
 ]
{11.1387, Null}

bmeshs // Length
10000

FreeQ[bmeshs, $Failed]
True

#["Wireframe"] & /@ RandomChoice[bmeshs, {10}]

Getting single MeshRegion using all 10000 cuboids seems to be faster than generating a MeshRegion object for each cuboid:

SeedRandom[1]
pts = RandomReal[100, {10000, 2, 3}];
cuboids = Cuboid @@@ pts;

cuboidsToMeshReg = Module[{indices, 
     faceindices = {{3, 7, 5, 1}, {1, 5, 6, 2}, {5, 7, 8, 6}, {4, 8, 7, 3}, 
       {2, 4, 3, 1}, {2, 6, 8, 4}}, 
     meshcoords = Join @@ (Tuples[Transpose@{##}] & @@@ #)}, 
    indices = Join @@ (faceindices + 8 # & /@ Range[0, Length[#] - 1]); 
    MeshRegion[meshcoords, Polygon @ indices]] &;

mreg = cuboidsToMeshReg @ cuboids; // AbsoluteTiming // First
0.157844
MeshCellCount[mreg, 2]
60000