I think spawn is the generally recommended way for this. (It's basically the thread approach, with a thread-pool)
https://nim-lang.org/docs/manual.html#parallel-spawn-spawn-statement
The tricky part is usually after your long-running task ends, you typically need to notify the UI-thread / main-loop and run additional code in there. I've never used libui-nim so I can't comment there but typically this sort of functionality already offered by the framework/library.
EDIT: Looking quickly at libui-nim, it looks like it has a proc called queueMain which may do this.