Mob apps can be extended with native code in four ways, accessed through two Mix tasks. This guide is a summary — the detailed contract per backend (how Cargo / Zigler / Pythonx normally work, what Mob changes for static linking, where the bundled Python runtime comes from on each platform, which workarounds are transient) lives in mob_dev's guides/nifs.md. Read that one before debugging a native build.

Two tasks, one decision

QuestionUse
"I want to write a NIF I'll name myself."mix mob.add_nif <name>
"I want to enable a pre-named Mob feature."mix mob.enable <feature>

The split tracks a real distinction. add_nif creates instances the user names (audio_engine, image_codec, crypto_utils) and can have many of. enable toggles singleton features with fixed implementations (pythonx, mlx, camera, notifications) — each exists at most once per app.

mix mob.add_nif <name>

Scaffolds a statically-linked NIF: Elixir stub, native skeleton appropriate to the chosen backend, :static_nifs entry in mob.exs, and regenerated dispatch table — one command, one diff.

mix mob.add_nif audio_engine                    # Elixir-only stub; you wire native side
mix mob.add_nif audio_engine --type c           # also drops c_src/audio_engine.c
mix mob.add_nif audio_engine --type rustler     # native/audio_engine/ Cargo crate + :rustler dep
mix mob.add_nif audio_engine --type zigler      # ~Z sigil in the stub + :zigler dep
mix mob.add_nif audio_engine --type rustler --demo   # also generates a demo screen

Why static linking? iOS App Store rejects bundled .dylib; Android RTLD_LOCAL hides the parent's enif_* symbols from a dlopen'd child. Both platforms force the same answer: link the NIF init function into the main app binary alongside libbeam.a. mob_dev handles the cross-compile and link automatically — you write the Rust/Zig/C, run mix mob.deploy --native, and the right .a ends up in the right place per arch.

Bringing in an existing Rust project (one crate or many — there's no upper limit) takes four manual steps documented in mob_dev's NIF guide. You don't need to be a Rust expert to follow it — the steps are copy-paste.

mix mob.enable <feature>

Toggles an optional feature with a fixed implementation. Patches mix.exs, platform manifests (Info.plist / AndroidManifest.xml), and any required source files in one Igniter run.

FeatureWhat it gives you
liveviewPhoenix LiveView mode — app renders a local web view
cameraCamera permission + capture API
photo_libraryPhoto picker + saving
file_sharingiOS Files-app integration + Android FileProvider
locationCoarse + fine location permissions and API
notificationsPush notifications (entitlement + APNs / FCM glue)
pythonxEmbedded CPython interpreter on iOS + Android
mlxApple MLX tensor math + EMLX Nx backend (iOS)
mix mob.enable camera photo_library     # multiple in one command
mix mob.enable pythonx                  # embeds CPython 3.13 on both platforms
mix mob.enable mlx                      # on-device tensor math (iOS, ~30 MB)

The pythonx and mlx features cost real bundle size (~70 MB and ~30 MB respectively). The rest are cheap (manifest entries + a few hundred lines of generated Elixir/Swift/Kotlin).

For exactly where Mob fetches the bundled CPython runtime from (BeeWare's Python-Apple-support for iOS, Chaquopy for Android, why two sources, what's identical between them) — see the Pythonx section of mob_dev's NIF guide.

What gets generated, where

For any NIF added via mob.add_nif <name> (regardless of --type):

lib/<app>/nifs/<name>.ex                    # Elixir stub module
mob.exs                                     # :static_nifs entry appended
priv/generated/driver_tab_ios.zig           # dispatch table (regenerated)
priv/generated/driver_tab_android.zig       # dispatch table (regenerated)

Plus, depending on --type:

c_src/<name>.c                              # --type c
native/<name>/Cargo.toml                    # --type rustler
native/<name>/src/lib.rs                    # --type rustler
native/<name>/.cargo/config.toml            # --type rustler (macOS link flags)

For mob.enable <feature> the file list varies per feature — see the individual feature docs via mix help mob.enable.

Where to dig deeper

TopicLocation
Per-backend mechanics, how each upstream library works, what Mob changes, transient workaroundsmob_dev/guides/nifs.md
Embedded CPython app integration (wheels, first-launch extraction, host-dev fallback)mob_dev/guides/python_embedding.md
MobDev.StaticNifs schema (arch values, per-arch symbol naming)MobDev.StaticNifs module doc
Full task referencesmix help mob.add_nif, mix help mob.enable