tezvyn:

Rust workspace versus single crate for plugins

AI-drafted, machine-checkedSource: interviewadvanced
WHAT IT TESTS

structuring a modular Rust system.

OUTLINE

a workspace gives incremental compilation, enforced API boundaries via a shared api crate, and per-plugin deps; a single crate is simpler but recompiles wholesale and blurs boundaries.

WHAT THIS TESTS Whether you understand that the crate is the unit of compilation, privacy and dependency, and can reason about how that drives a plugin architecture's build times and boundaries.

A GOOD ANSWER COVERS In a workspace, each plugin is its own crate and all depend on a shared plugin-api crate that defines the traits and types plugins implement. Because crates compile independently and are cached, changing one plugin recompiles only that crate and its dependents, not the whole tree, which keeps incremental builds fast at scale. The plugin-api crate becomes an explicit, versionable contract; plugins can only use its public surface, enforcing stable boundaries. Each plugin crate also declares its own dependencies and feature flags, so unrelated plugins do not drag in each other's deps. A single crate with plugins as modules is simpler to set up and lets code share private internals freely, but the crate recompiles as one unit so any change rebuilds everything, and module privacy is weaker than crate boundaries, so plugins can entangle.

COMMON WRONG ANSWERS Thinking modules compile incrementally like separate crates. Ignoring that a shared api crate enforces a contract. Believing workspaces always add overhead with no benefit. Conflating feature unification concerns.

LIKELY FOLLOW-UPS How does the plugin-api crate enable stable trait objects. How does Cargo feature unification behave across a workspace. Static versus dynamic plugin loading. How do you version the api crate.

ONE CONCRETE EXAMPLE A data pipeline has twenty transform plugins. As a workspace, plugin-api defines a Transform trait; each transform is a crate depending only on plugin-api. Editing one transform recompiles just that crate, and a plugin needing a specific parser pulls it in without affecting the others. As a single crate, the same twenty live as modules; touching one forces the entire crate to rebuild and any module can call another's internals, eroding the plugin boundary over time.

Read the original → doc.rust-lang.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.