Open source · self-hostable

Static-site simple.
Real-app capable.

Crisptastic is a web framework for sites that outgrew static hosting. Keep writing a folder of pages — then add a login, a checkout, file uploads or a database read by declaring them. There is no separate backend to build, secure or keep running.

checkout/index.html.crisp
@call user = auth.require()

@call order = payments.checkout({
  price: "pro_annual",
  customer_email: user.email,
  success_path: "/welcome/"
})

@redirect order.value.url, status: 303

The whole checkout route. No API server, no Stripe SDK, no secret plumbing — the framework owns all of it.

Why it exists

Static site generators stop where the app begins.

Astro, Hugo, Eleventy and friends make content sites a joy — until the site has to do something. The moment you need authentication, payments, saved data or uploads, you are standing up a second project: an API server, a database, provider SDKs, a place to keep secrets, a deploy pipeline, a process to keep alive. Every dynamic site rebuilds that same plumbing, and re-makes the same security mistakes.

Crisptastic keeps the folder-of-pages model and moves the plumbing into the framework. The dynamic parts of your site become declarations — a few lines that say what a page needs — instead of code you write, wire together and operate.

How it works

Three moves, start to production.

01

Write pages

Routes, components and layouts are just files in a directory. Dynamic values come from a typed request and session context. crisptastic dev serves a live site with the exact behaviour production will use.

02

Declare what a page needs

Name a capability — auth, data, payments, files, images, messaging — and an operation. The framework owns the provider protocol, the credentials, the retries, the redirect rules and the security.

03

Deploy one file

crisptastic deploy compiles pages, assets and config into a single immutable, encrypted Capsule and ships it to a host that routes it by domain. Secrets are injected at the host and never written to disk.

What's in the framework

A small set of concepts. Nothing else to assemble.

Pages, components & layouts

A small template syntax: interpolation, conditionals, loops, build-time includes and a typed context. Server-rendered by default — no client framework is shipped to the browser unless you add one.

Capabilities

Auth, data, payments, files, images and messaging — one way to call them, with the provider (Stripe, Auth0, S3, your data API) owned by the framework, not your code.

Data shaping with SDA

Reshape an awkward API response into exactly the shape a page wants — declaratively, in one expression — instead of nested template logic or a graveyard of one-off transformer functions.

One-command deploy

A deterministic build, an encrypted Capsule, atomic activation, and a multi-tenant host that sits behind your reverse proxy and routes many sites by domain.

Secure by construction

Undeclared capabilities and unknown domains fail closed. Provider credentials never reach a page or the browser. Application secrets never touch disk — losing them is designed to require reinjection.

The same behaviour everywhere

Local development, tests and production run the identical execution model. crisptastic dev is production with watch mode, not an approximation of it.

A page that does something

This is a complete account page.

It requires a signed-in user, reads their orders from a declared data API, and reshapes the response for display. There is no controller, no serializer, no ORM model, and no client to render — the file is the endpoint.

The data capability attaches the right credentials after policy checks; the page only ever sees normalised, bounded values.

account/index.html.crisp
@call user = auth.require()

@call orders = data.orders_list({ customer: user.id })

@shape recent = orders.value with "
  [ .items | sort_by(-created) | take(5)
    | { id, total, when: created } ]
"

<h1>Hi, {{= user.name }}</h1>

@for (o of recent) {
  <a href="/orders/{{= o.id }}">
    {{= o.when }} — {{= o.total }}
  </a>
}

Scope

What Crisptastic is not.

Not a static site generator

Pages execute per request on the server. You get dynamic behaviour, sessions and per-user output — not a pre-built bundle of HTML.

Not a container platform

A Capsule is one declared application, not an arbitrary process. There is no Dockerfile and nothing to orchestrate.

Not a backend-as-a-service

Your records, files and images live in your own database and storage. Crisptastic holds the credentials and enforces policy; it keeps no authoritative data of its own.

Not an ORM

You talk to a declared data API with runtime credentials, not raw SQL or a query builder wired into your pages.

Build a site that does things.

Install the binary, run crisptastic dev against a folder, and add your first capability in a line. The whole authoring surface fits on one page.