Ferrite Functions run your application logic as isolated Rust processes. Each
function receives only the named platform handles declared in ferrite.json;
there are no ambient database credentials, arbitrary sockets, or hidden cloud
service clients.
Create a function
ferrite new hello receipts-api
cd receipts-api
ferrite dev
The application implements FerriteApp and obtains resources from
AppContext:
#![forbid(unsafe_code)]
use std::io;
use ferrite_app::{app_main, AppContext, FerriteApp};
struct Receipts;
impl FerriteApp for Receipts {
async fn run(ctx: AppContext) -> io::Result<()> {
let mut requests = ctx.queue("requests")?;
loop {
let Some(lease) = requests.poll_wait(1_000).await? else { continue };
// Decode, authorize, apply domain logic, then acknowledge.
requests.ack(lease.token).await?;
}
}
}
fn main() { app_main::<Receipts>() }
Lifecycle and scale
One OS process runs each app instance. Ferrite supervises the process, applies authoritative timeouts, and kills the process group if it exceeds its boundary. Scale adds competing instances against the same durable resources:
ferrite dev --instances 3
After deployment, scale from the Dashboard or call the Ferrite MCP scale
tool with the app name and desired instance count. Verify the result with
ferrite status receipts-api.
Use queue leases and idempotency for effects that may be retried after a crash.
Run ferrite dev --chaos 5 to make this behavior visible before deployment.
Compute limits
Declare memory and CPU in the app manifest. Admission rejects a configuration that violates platform bounds or budget rules before it starts. Functions do not own durable state; Store, Queue, Streams, Transactions, and Object Storage survive function replacement.
Continue with Routing, Queues, or Deployments.