Procedures-Only Servers with No Database
Not every CrateStack service owns data. A procedures-only facade in front of another system, a stateless computation endpoint, or a pure business-logic layer has no need for aPgPool — but it still wants generated routes, procedure policies, and a typed client. datasource { provider = "none" } plus include_server_schema!("…", db = None) gives you exactly that: a server macro that never threads a database connection through, backed by a facade crate that never links sqlx in the first place.
When to Reach for It
- a procedures-only RPC facade in front of another service (another CrateStack schema, a third-party API, an internal gRPC backend)
- a stateless computation endpoint — validation, scoring, transformation — with no persisted state
- pure business logic that composes calls to other systems instead of owning a table
model, this is the wrong shape — reach for db = Postgres (cratestack-pg) or the embedded SQLite backend (cratestack-rusqlite) instead; see Offline-First with Embedded SQLite.
The Hard Constraint
A schema withdatasource { provider = "none" } can never declare a model block. This is enforced at schema-check time, not left as a runtime surprise: the semantic checker rejects the schema and names the offending model directly.
provider = "none" schema has nothing to render a table for, so the checker treats declaring one as a schema error rather than quietly ignoring it.
Add the Dependency
cratestack-api is a third facade crate, structurally parallel to cratestack-pg and cratestack-sqlite: same rename-via-package = pattern, same re-exported macro surface, but sqlx and cratestack-sqlx are genuinely absent from its dependency graph — not a Cargo feature you have to remember to turn off.
Already on Both paths work and neither is being removed.
cratestack-pg and just want to shed sqlx from a database-free build without switching facades? cratestack-pg’s postgres feature is default-on and gates cratestack-sqlx out when you opt into default-features = false:cratestack-api is the leaner default for anyone starting a database-free service from scratch; cratestack-pg with default-features = false is there for teams that already standardized on that facade.Schema
Setprovider = "none" on the datasource block. Everything else — auth, procedure, @allow/@deny, transport rpc or the default REST binding — works exactly as it does on a database-backed schema:
Procedure-level
@allow / @deny policies never depended on a database connection to evaluate — they check auth() and argument shape, both of which exist independent of provider. They keep working unchanged on provider = "none" schemas.Minimal Setup
() in third position is the computed-field resolver, and () is the right value
whenever the schema declares no @computed fields. A db = None schema can still declare
them — on a type returned by a procedure — in which case pass your resolver here instead;
see Computed Fields.
Cratestack::builder() takes zero parameters here — there’s no pool to configure, no connection string to thread through, no PgPool anywhere in the type. Compare this to the db = Postgres path (see Quickstart), where the builder takes a pool and every generated model delegate borrows it; on db = None there are no model delegates to borrow it, so the builder has nothing left to ask for. Only procedure_router gets mounted — there’s no model_router to nest alongside it, because there are no models.
What You Give Up, What Still Works
Given up, structurally, not “not yet”:- no models, ever, in this schema. Not a temporary limitation — the checker enforces it at compile time, and a schema built this way has no table-backed storage to add one to. If you need a model later, that’s a different schema (or a different
datasource), not an upgrade path for this one.
transport rpc(POST /rpc/{op_id}+POST /rpc/batch) or the default REST procedure route (POST /$procs/<name>) — see RPC transport- procedure-level
@allow/@denypolicies, since those only ever evaluatedauth()and argument shape - generated Rust/Dart/TypeScript client stubs via
include_client_schema!against this schema, from another service’s point of view
Read Next
./rpc-transportfor the RPC binding this shape pairs naturally with./offline-first-sqlitefor the embedded SQLite backend, if your service turns out to need local storage after all../overview/current-statefor wheredb = Noneand thecratestack-apifacade sit in the current implemented surface