PocketPages Logo

PocketPages

brew install pockethost/tap/pocketbase
pocketbase pages create myapp

No-Build Multi-Page Apps for PocketBase

<!-- pb_pages/index.ejs -->
<%= `Hello, PocketPages!` %>
http://localhost:8090
Hello, PocketPages!

Why PocketPages is Better

Zero compilation, zero bundling, zero build steps. Just write code and deploy - frontend and backend.

Zero Build Steps

No compilation anywhere. Write HTMX, Alpine.js, or VanJS and see changes instantly.

Server-Side Rendered

Pages render on the server using PocketBase JSVM. Fast, SEO-friendly, and reliable.

PocketBase Native

Built into PocketBase CE: routing and templates in Go, your page code in PocketBase's JS VM. Your data, auth, and APIs are right there.

Why Multi-Page Apps Matter

While SPAs dominate the conversation, MPAs offer proven benefits for most web applications. PocketPages brings this architecture to PocketBase's powerful backend.

✓ MPA Advantages

  • Instant Page Loads: Server renders HTML, browser shows content immediately
  • SEO by Default: Search engines get fully rendered HTML
  • Progressive Enhancement: Works without JavaScript, enhanced with it
  • Simpler Mental Model: Each URL = one page, like the web was designed
  • Zero Compilation: No build steps anywhere - frontend or backend
pb_pages/users/[id].ejs
<% // Server-side data loading in PocketBase JSVM
const user = $app.findRecordById('users', params.id)
%>

<!-- Template renders with live data -->
<%= user.get('name') %> joined <%= user.get('created') %>

PocketBase JSVM Integration

Direct access to your database, authentication, and APIs server-side.

Perfect for No-Build Frontend

Drop in your favorite no-build frontend library and start building. No webpack configs, no bundlers, no compile steps.

htmx

High power tools for HTML

Alpine.js

Minimal framework for HTML

Datastar

Reactive UI with data binding

VanJS

Ultra-lightweight reactive UI

Vanilla JS

Pure JavaScript, no dependencies

HTMX + PocketPages
<%- include('header.ejs') %>

<div hx-get="/api/todos"
     hx-trigger="load"
     hx-target="#todo-list">
  Loading todos...
</div>

<div id="todo-list"></div>
Alpine.js + PocketPages
<div x-data="{ todos: <%= JSON.stringify(todos) %> }">
  <template x-for="todo in todos">
    <div x-text="todo.title"
         :class="{ 'completed': todo.done }">
    </div>
  </template>
</div>
Datastar + PocketPages
<input type="text"
       name="message"
       data-bind:message />

<button data-on:click="@get('/api/chat')">
  Send
</button>

<div id="chat-box">
  <% for (const msg of ctx.store('messages')||[]) { %>
    <div><%= msg.message %></div>
  <% } %>
</div>