Everything you need to ship modern apps, fully integrated and type-safe.
The Reactive Engine. Browser-resident state management without the hydration nightmares.
Shadcn-style components. Beautiful, accessible, and server-rendered components.
1000+ crisp, consistent SVG icons optimized specifically for the Prisma PHP ecosystem.
Next.js-style routing, Type-safe ORM, and CLI tooling. The foundation of your app.
Import your custom UI or PHPX library components once, then reuse them anywhere with standard HTML syntax. Total control in your hands.
<?php
use Lib\PHPXUI\{Label, Input, Button};
?>
<!-- HTML-first tags from component-map.json -->
<x-label for="email">Email</x-label>
<x-input id="email" type="email" />
<x-button variant="outline" as-child="true">
<a href="/docs">Get Started</a>
</x-button>
Ditch raw SQL and brittle strings. Write expressive PHP queries with IDE autocompletion, real types, and instant feedback — iterate faster and ship with confidence.
$users = $prisma->user->findMany([ 'where' => ['active' => true], 'include' => ['posts' => true], ]);
Stop writing DTOs and mapping layers. With Prisma PHP, your database schema is your frontend state. The JSON model stays perfectly in sync across the stack.
pp.state() and let PulsePoint handle the DOM.
<?php
// 1. Fetch DB Model (Server)
use Lib\Prisma\Classes\Prisma;
$prisma = Prisma::getInstance();
$users = $prisma->user->findMany();
// $users is now a structured Array/JSON model
?>
// 2. Render UI
<ul>
<template pp-for="user in users">
<li key="{user.id}">{user.name}</li>
</template>
</ul>
// 3. Hydrate (State = DB Model)
<script>
const [users, setUsers] = pp.state(<?php echo json_encode($users); ?>);
// "users" here has the exact same fields as your DB
</script>
Mark a PHP function with #[Exposed] and call it from the browser with
pp.rpc(...). CSRF, origin checks, auth, roles and rate limiting are enforced by the
runtime — and the same call handles file uploads and SSE streaming.
<?php
use PP\Attributes\Exposed;
use PP\Validator;
#[Exposed(limits: '20/min')]
function addTodo($data)
{
$title = Validator::string($data->title ?? '');
if ($title === '') {
return ['success' => false, 'error' => 'Title is required.'];
}
return ['success' => true, 'title' => $title];
}
<script>
const [title, setTitle] = pp.state('');
const [error, setError] = pp.state('');
async function submit() {
try {
const res = await pp.rpc('addTodo', { title });
if (!res.success) return setError(res.error);
setTitle('');
setError('');
} catch (e) {
// 401 / 403 / 429 / 500 reject with an Error
setError(e.message);
}
}
</script>
A function without #[Exposed] is invisible to the client — the runtime answers 404.
Make the function a generator and Prisma PHP turns the response into SSE. Read it from onStream.
For chat, presence and live feeds use pp.socket(name, args, handlers) instead of polling.
With PulsePoint, you don't need complex build steps or hydration logic. Define your state in the browser and bind it directly to your PHPX components.
Use pp.state to handle DOM updates instantly.
Your logic stays in PHP. Your UI stays interactive. No context switching.
<h1>Count is: {count}</h1>
<button
onclick="setCount(count + 1)"
disabled="{count >= 10}">
Increment
</button>
<button
onclick="setCount(count - 1)"
disabled="{count <= 0}">
Decrement
</button>
<script>
const [count, setCount] = pp.state(0);
</script>
Help us improve your experience
{successMessage}
Operating hours: Mon-Fri, 9am - 5pm EST