nseaSeb

nseaSeb

I’ve just put together a small POC exploring PDF inspection from Elixir/Phoenix:

The idea is pretty simple: drag & drop a PDF in a Phoenix LiveView application, pass it to pdf2md from Firecrawl’s pdf-inspector, and display the extracted information (PDF type, number of pages, tables, Markdown, etc.).

The interesting part for me was not really the PDF processing itself, but how to integrate the Rust component with Elixir.

For this POC, I deliberately avoided a NIF.

Instead, the Rust binary is invoked through an OS Port:

Port.open(
  {:spawn_executable, path},
  [:binary, :exit_status, args: args]
)

The Rust binary is vendored in priv/rust_bin/bin/, so the Phoenix application can invoke it directly.

This feels like a rather nice boundary for this kind of workload:

  • Elixir/Phoenix remains responsible for the application and supervision.

  • Rust does the CPU-heavy/PDF-specific work.

  • No NIF means no risk of blocking or crashing the BEAM VM from native code.

  • The interface between the two sides remains very explicit.

Obviously, there are trade-offs compared with a NIF: process startup, serialization, IPC overhead, error handling, deployment, etc.

So I’m curious about how others in the Elixir ecosystem would approach this.

Would you use an OS Port for this kind of integration, or would you go for a NIF / Rustler?

This is only a POC for now, but I’m particularly interested in feedback on the architecture rather than the PDF extraction itself.

Showing Posts 1 to 8

jc00ke

jc00ke

I think a port is a good option for this, without the downsides of a NIF, mainly that crashes can take down the BEAM. I recently implemented this CNode pattern, which I think is a great option for this kind of interop. In my case, instead of wrapping with Crystal, I used erl_interface directly in my Go and used zig to build the Go project as a CGo binary. I should write that up someday. I never went back to it and never got beyond the PoC “echo”, but I really like the pattern.

nseaSeb

nseaSeb OP

I agree for the port, more latency than nif I guess but can’t crash the beam.

dimitarvp

dimitarvp

Well, anecdotal evidence: I never had a Rust program crash on me.

The only times that actually happened was due to a lack of memory and the Linux OOM reaper killing them.

I do like the architecture though; ports are awesome and in this case when you have an assembly line to process documents, it’s absolutely the better pattern to use – and not super difficult to rework to distributed clusters of nodes, too.

conradwt

conradwt

I like the overall architecture and thanks so much for sharing.

mogery

mogery

Hey! This is a cool project. Disclosure: I work at Firecrawl.

A note regarding crashes: We run pdf-inspector in production on every PDF we encounter via a Node.js native addon (via napi-rs), which has crash characteristics very similar to NIF. We deliberately avoid having any code to the library that can cause panics. :slight_smile:

nseaSeb

nseaSeb OP

Hello, thank you—it’s really nice to receive your comment. I have no doubt that it’s stable; in my opinion, the gain from using Nifs doesn’t matter here, but perhaps I’m mistaken?

derek-zhou

derek-zhou

Crash isolation is only part of the considerations. The others are:

  • Do you need to maintain state at the native side across invocations?
  • Does the native side has a significant async part?
  • Does the native side run for significant amount of time?
dimitarvp

dimitarvp

That question itself made me skip shelling out to Port-s many times in the past btw. But with time I started seeing that with a good orchestrator built on top of Oban / ObanPro you can just update state in the DB f.ex. “job for PDF file blah_blah_173.pdf is still ongoing; this is the remote job ID (can be anything, even Fly.IO VM ID) – check it in 20 minutes and if it’s still not done, kill and retry”.

Of course, orchestration itself is not always as easy but now in the age of LLMs we have multiple excellent offerings in addition to Oban / ObanPro with different tradeoffs for almost every scenario so this is even more readily available than before.

(Though quite honestly, when you have an excellent durable orchestration library that also makes the argument for working inside the BEAM again because your worst-case scenario is to orphan a PDF generation job which is far from the end of the world; you’ll try to find the orphaned file / job and just resume.)

— All posts loaded —

Where Next? Top

Trending in Discussions Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
axelson
Hi there! :wave: @frigidcode and I (but mostly him) have been running an Elixir Book club, we’re almost done with Designing Elixir Syste...
New
achempion
I’ve been using Emacs as my main code editor for more than a two years. It’s a custom build version although I’ve tried doom emacs and sp...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New
jtormey
Lately I’ve been thinking about how to organize components as a LiveView application grows. One of the pain points I’ve found (for myself...
New
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
georgeguimaraes
Just published claude-code-elixir, a plugin marketplace for Claude Code with Elixir support. These are the plugins I’ve been using for my...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews