ZQL on the Server
Custom Mutators use ZQL on the server as an implementation detail, but you can also use ZQL on the server directly, outside of Custom Mutators.
This is useful for a variety of reasons:
- You can use ZQL to implement standard REST endpoints, allowing you to share code with custom mutators.
- You can use ZQL as part of schema migrations.
- In the future (but not yet implemented), this can support server-side rendering
Here's a basic example:
import {
PushProcessor,
ZQLDatabase,
PostgresJSConnection,
TransactionProviderInput,
} from "@rocicorp/zero/pg";
const db = new ZQLDatabase(
new PostgresJSConnection(
postgres(
must(
process.env.ZERO_UPSTREAM_DB as string,
"required env var ZERO_UPSTREAM_DB"
)
)
),
schema
);
// This is needed temporarily and will be cleaned up in the future.
const dummyTransactionInput: TransactionProviderInput = {
clientGroupID: "unused",
clientID: "unused",
mutationID: 42,
upstreamSchema: "unused",
};
db.transaction(
async (tx) => {
// await tx.mutate...
// await tx.query...
// await myMutator(tx, ...args);
},
dummyTransactionInput
);
If ZQL does not have the featuers you need, you can use tx.dbTransaction
to drop down to raw SQL.
SSR
Although you can run ZQL on the server, Zero does not yet have the wiring setup in its bindings layers to support server-side rendering (patches welcome though!).
For now, you should use your framework's recommended pattern to prevent SSR execution.
Next.js
Add the use client
directive.
SolidStart
Wrap components that use Zero with the
clientOnly
higher-order component.
The standard clientOnly
pattern uses dynamic imports, but note that this
approach (similar to React's lazy
)
works with any function returning a Promise<{default: () => JSX.Element}>
. If
code splitting is unnecessary, you can skip the dynamic import.
TanStack Start
Use React's lazy
for dynamic
imports.