I suggest you have your function return a ptr to the first element and a length instead and make sure that while your function is running a variable holds on the seq so it's not garbage collected.
A seq at a low-level is: * 2 ints (C int_64t on 64-bit arch) for tlength and reserved space * a pointer to a contiguous heap-allocated array of elements See: [https://github.com/nim-lang/Nim/blob/721bf7188bfff3a3ae1db44bece57cca3dfe8461/lib/system.nim#L502-L508](https://github.com/nim-lang/Nim/blob/721bf7188bfff3a3ae1db44bece57cca3dfe8461/lib/system.nim#L502-L508) when not defined(JS) and not defined(gcDestructors): type TGenericSeq {.compilerproc, pure, inheritable.} = object len, reserved: int when defined(gogc): elemSize: int PGenericSeq {.exportc.} = ptr TGenericSeq Run This changes a bit when using destructors or Javascript or the Go GC. The way to use seq in FFI is ## raw example let a = @[1, 2, 3, 4, 5] let a_ptr = a[0].unsafeAddr # cast to ptr UncheckedArray if you want array indexing # if a is a var a[0].addr is enough ## C Interface function proc foo(a: seq[int]): tuple[p: ptr int, len: int] {.exportc.} = result = (a[0].unsafeAddr, a.len) Run
