I’m pretty new to Julia and was wondering what the preferred practice for storing something like a bunch of coordinates, mesh triangles or graph edges?

Say I want to store edges in a graph. The vertices are labelled by indices 1,2,3,…
Would I want to be storing the edges as 2-tuples in a Vector{Tuple{Int, Int}}, since I know that each edge is stored as exactly 2 vertex indices?
Or would it be better to store the edges in a 2-by-N matrix structure Matrix{Int} (each edge stored as a column, since afaik looping over columns is preferred over rows)?
Or is there a third way I don’t know of which is better than both of the above?

These in fact have the same storage, so you can use either and convert for free. A third option would be StaticArrays, which are essentially tuples wrapped up to look like vectors:

julia> mat = rand(1:99, 2,3)
2×3 Matrix{Int64}:
19 7 4
9 11 52
julia> reinterpret(reshape, Tuple{Int,Int}, mat) # with Julia 1.6, or Compat.jl
3-element reinterpret(reshape, Tuple{Int64, Int64}, ::Matrix{Int64}) with eltype Tuple{Int64, Int64}:
(19, 9)
(7, 11)
(4, 52)
julia> using StaticArrays
julia> svecs = [SVector(rand(1:99), rand(1:99)) for _ in 1:3]
3-element Vector{SVector{2, Int64}}:
[7, 17]
[11, 36]
[69, 80]
julia> reshape(reinterpret(Int, svecs),2,:) # works on Julia <= 1.5 too
2×3 reshape(reinterpret(Int64, ::Vector{SVector{2, Int64}}), 2, 3) with eltype Int64:
7 11 69
17 36 80

What the best solution is, depends on what you want to do. If you intend to do a lot of operations on the 2-vectors, then a vector of StaticVectors could be very advantageous. If you are doing ordinary matrix operations, then a matrix is probably better.