Client scripts

Code inside cs`…`, written in your server's files and run on the phone.

server/Home.tsx
import { type Client, cs } from "@backtickjs/core";
import { Text, View } from "@backtickjs/react-native";
// An expression: a value the phone computes, with the phone's own clock.
const greeting: Client<string> = cs`new Date().getHours() < 12
? "Good morning"
: "Good afternoon"`;
// A function the phone calls.
const formatPrice: Client<(price: number) => string> = cs`(price: number) =>
price.toLocaleString("en-US", { style: "currency", currency: "USD" })`;
export async function Home() {
const total = 13.5;
// Statements, ending in what the script is: here, the screen.
return cs`{
const label = $formatPrice($total);
return (
<$View style={{ padding: 24, gap: 8 }}>
<$Text>{$greeting}</$Text>
<$Text>Your total is {label}.</$Text>
</$View>
);
}`;
}

A client script is code inside cs`…`. It's written in your server's files, but it runs on the phone. To your server, a script is a value, a Client<T>: something the phone will compute as a T.

Three shapes

A script is an expression, a block of statements, or a function:

  • An expression, like greeting: cs`new Date().getHours() < 12 ? …`. It's a Client<string>, computed on the phone, so it reads the phone's clock rather than your server's.
  • A block of statements, like the script Home returns: cs`{ … }`. Its return is what it is, here the screen. Use it when the script needs variables of its own.
  • A function, like formatPrice: cs`(price: number) => …`. It's a Client<(price: number) => string>, a function the phone calls. A function that returns JSX is a client component.

TypeScript infers each type, as Client<string> here; the annotations in the example only show them.

Full JavaScript

A script is ordinary modern JavaScript and TypeScript: loops, try/catch, async functions, classes, destructuring, and JSX. It runs on the phone with the phone's globals: fetch, setTimeout, JSON, Math, Intl, console and the rest.

What a script can see

A script sees its own code and the phone's globals, but not the file around it: that's your server's code. To use a value from your server, splice it with $, as $total and $formatPrice do. Forget the $, and TypeScript looks for a global by that name:

server/Forgot.tsx
import { cs } from "@backtickjs/core";
import { Text } from "@backtickjs/react-native";
export async function Home() {
const total = 13.5;
return cs`(
// @ts-expect-error: Property 'total' does not exist on type 'GlobalThis'.
<$Text>Your total is {total}.</$Text>
)`;
}
Property 'total' does not exist on type 'GlobalThis'.

Splices covers what can cross, and how.

Compiled with your server

Scripts are compiled when your server loads its files, by @backtickjs/node-plugin on Node or @backtickjs/bun-plugin on Bun, which a new project already runs. Type errors in a script show in your editor and in npm run typecheck; see Type checking.