Building Data-Driven Web Apps Without the Backend Complexity
Facet brings Java's production-grade reliability with PHP's rapid development experience. Map MongoDB collections to HTML templates through convention—no controllers, no ORMs, just templates. Hot reload during development, deploy as a single JAR or native binary with sub-100ms startup.
The Problem
Modern web development forces you to choose:
- Spring Boot? Powerful but complex—controllers, services, repositories, configuration files, dependency injection
- Laravel/Django/Rails? Fast development but requires careful operational tuning for production scale
- Modern SPAs? Build separate frontend and backend, manage state, loading states, API orchestration
- Headless CMS? Pay for features you don't need, locked into proprietary systems
What if you could get Java's performance with PHP's simplicity?
Meet Facet
Facet is a data-driven web framework that transforms MongoDB REST APIs into server-rendered HTML. Convention over configuration means your collections become web pages automatically—no backend code needed.
Hybrid API/UI from the same endpoint:
# JSON for APIs
curl -H "Accept: application/json" http://localhost:8080/shop/products
# HTML for browsers
curl -H "Accept: text/html" http://localhost:8080/shop/products
The same code, same data, different representation. Templates are opt-in—add HTML rendering only where you need it. Your REST API remains unchanged.
How It Works
1. Convention-Based Template Resolution
Your template structure mirrors your API paths:
Request: GET /shop/products
Accept: text/html
Facet looks for:
1. templates/shop/products/index.html ✓ (found!)
2. templates/shop/index.html (parent fallback)
3. templates/index.html (global fallback)
4. No template → return JSON (API unchanged)
SSR is opt-in per resource. Add templates only where you need HTML.
2. Rich Template Context
Templates automatically receive:
<h1>{{ database }}/{{ collection }}</h1>
{% for item in items %}
<div class="product">
<h3>{{ item.data.name }}</h3>
<p>{{ item.data.description }}</p>
<span>${{ item.data.price }}</span>
</div>
{% endfor %}
{# Pagination built-in #}
{% if totalPages > 1 %}
<nav>
{% for p in range(1, totalPages + 1) %}
<a href="?page={{ p }}">{{ p }}</a>
{% endfor %}
</nav>
{% endif %}
Context includes: pagination, authentication, permissions, MongoDB query parameters, and more.
3. First-Class HTMX Support
Facet automatically detects HTMX requests and routes to fragment templates:
Full page template:
{% extends "layout" %}
{% block main %}
<div id="product-list">
{% include "_fragments/product-list" %}
</div>
<form hx-get="/shop/products"
hx-target="#product-list"
hx-indicator="#loading">
<input name="filter" placeholder="Search...">
<button type="submit">Search</button>
</form>
{% endblock %}
Fragment template (templates/_fragments/product-list.html):
{% for item in items %}
<article>
<h3>{{ item.data.name }}</h3>
<p>{{ item.data.description }}</p>
<span>${{ item.data.price }}</span>
</article>
{% endfor %}
When HTMX sends HX-Target: #product-list, Facet automatically renders just the fragment—no backend code needed.
Quick Start
1. Start Facet and MongoDB
curl -O https://getfacet.org/docker-compose.yml
docker-compose up -d
2. Create Database and Add Data
# Create collection
curl -X PUT http://localhost:8080/shop/products
# Insert products
curl -X POST http://localhost:8080/shop/products \
-H "Content-Type: application/json" \
-d '[
{"name": "Laptop", "price": 999},
{"name": "Mouse", "price": 29}
]'
3. Create Template
mkdir -p templates/shop/products
templates/shop/products/index.html:
<!DOCTYPE html>
<html>
<head>
<title>Products</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
<script src="https://unpkg.com/htmx.org@2.0.8"></script>
</head>
<body>
<main class="container">
<h1>Products</h1>
<div id="product-list">
{% for item in items %}
<article>
<h3>{{ item.data.name }}</h3>
<span>${{ item.data.price }}</span>
</article>
{% endfor %}
</div>
</main>
</body>
</html>
4. Visit in Browser
open http://localhost:8080/shop/products
✨ That's it! You have a working web application with zero backend code.
Real-World Example
The product catalog example demonstrates a complete application with:
- ✅ MongoDB data binding and display
- ✅ Search and filtering with MongoDB queries
- ✅ Pagination with preserved query parameters
- ✅ HTMX partial updates for dynamic search
- ✅ Authentication & role-based access control
- ✅ Full CRUD operations (admin only)
Try it yourself:
git clone https://github.com/SoftInstigate/facet.git
cd facet/examples/product-catalog
docker-compose up
Visit http://localhost:8080/shop/products
Login credentials: admin / secret
The example includes hot-reload—edit templates and see changes instantly without restart.
Why This Approach?
For Simple Projects
- No backend coding - Templates directly render API data
- Convention over configuration - No route wiring, templates map to URLs automatically
- Hot reload - Edit templates, refresh browser, see changes instantly (no build step, no webpack, no npm scripts)
- Progressive enhancement - Start with JSON API, add HTML where needed
For Complex Projects
- Flexible layouts - Different layouts per application area
- Framework agnostic - Use any CSS/JS framework (React, Alpine.js, Tailwind, etc.)
- HTMX native - Build SPA-like experiences with server-side rendering
- SEO friendly - Server-rendered HTML from the start
- Extensible - Add custom logic via RESTHeart plugins (Java or JavaScript via GraalVM)
For Teams
- Separation of concerns - Web devs work on templates, backend devs on API
- No deployment coupling - Templates update without backend changes
- Gradual adoption - Add HTML to existing APIs incrementally
Architecture Benefits
Facet leverages RESTHeart's production-grade features:
- MongoDB REST API with full query support
- Authentication (JWT, Basic Auth, OAuth, LDAP)
- Authorization with fine-grained ACL
- WebSocket and Change Streams for real-time data
- GraphQL support (coming soon to Facet templates)
- Plugins for custom business logic
You get enterprise-grade infrastructure without building it yourself.
When to Use Facet
Great fit:
- ✅ Content-driven applications (blogs, catalogs, dashboards)
- ✅ Internal tools and admin panels
- ✅ MongoDB-backed applications
- ✅ Projects prioritizing SEO and fast initial load
- ✅ Teams wanting to avoid frontend/backend coordination
Not ideal for:
- ❌ Highly interactive applications with complex client-side state
- ❌ Non-MongoDB databases (Facet is MongoDB-specific)
- ❌ Applications requiring real-time collaboration (though RESTHeart supports WebSockets)
How Does Facet Compare?
vs. Spring Boot and Java MVC Frameworks
Spring Boot is powerful but complex: controllers, services, repositories, configuration files, build tools, and dependency injection.
Facet eliminates this boilerplate:
- ✅ MongoDB collections automatically become web pages through convention-based templates
- ✅ No controllers, no ORMs, no XML configuration
- ✅ Hot reload templates without restart
- ✅ Get Java's performance without Java's ceremony
Performance: Same JVM benefits (sub-100ms startup with native images, ~50MB memory footprint, handle thousands of concurrent connections)
When to use Spring Boot instead: Complex business logic requiring extensive service layers, non-MongoDB databases, or team already invested in Spring ecosystem
vs. Laravel, Django, Rails
PHP and Python frameworks are great for rapid development, but they require careful operational tuning for production scale.
Facet gives you the same rapid development experience:
- ✅ Convention over configuration
- ✅ Hot reload during development
- ✅ Minimal boilerplate
But runs on the battle-tested JVM:
- ✅ Deploy with confidence—no PHP-FPM tuning, no WSGI complexity
- ✅ Sub-100ms startup with native images
- ✅ ~50MB memory footprint
- ✅ Handle thousands of concurrent connections out of the box
When to use Laravel/Django instead: Team expertise in PHP/Python, need for framework-specific packages, or using PostgreSQL/MySQL
vs. Modern SPAs (React, Vue, Angular)
SPAs excel at highly interactive applications but add complexity:
Facet simplifies:
- ✅ Server-rendered HTML by default (SEO-friendly from day one)
- ✅ No state management, loading states, or API orchestration needed
- ✅ HTMX for SPA-like interactivity without build tools
- ✅ Progressive enhancement—add interactivity where needed
When to use SPAs instead: Highly interactive applications with complex client-side state (think Gmail, Figma, or real-time collaboration tools)
vs. Headless CMS (Contentful, Strapi)
Headless CMSs provide content modeling and APIs:
Facet offers:
- ✅ More flexibility—not limited to content modeling paradigms
- ✅ Direct MongoDB access with full query power
- ✅ Open source—run anywhere, no vendor lock-in
- ✅ No licensing costs
When to use Headless CMS instead: Non-technical content editors need a UI, or you need advanced content workflows and localization
Performance & Deployment
Choose Your Runtime
GraalVM JDK (with JavaScript extensibility):
- ~1s startup time
- ~150MB memory footprint
- Support for JavaScript plugins via GraalVM
Native Image (maximum performance):
- <100ms startup time
- ~50MB memory footprint
- Single binary, no Java installation required
Both configurations handle thousands of concurrent requests efficiently. MongoDB queries stream directly to templates—no ORM overhead.
Production Features
- Template caching - Compiled templates cached for optimal performance
- ETag support - Browser caching with 304 Not Modified responses
- MongoDB indexes - RESTHeart leverages your database indexes
- Stateless design - Horizontal scaling is trivial
- Single artifact - Deploy as JAR or native binary
- 12-factor compliant - Environment-based configuration, health checks built in
Deployment Options
Deploy anywhere:
- Docker containers
- Kubernetes clusters
- AWS, Azure, Google Cloud
- Bare metal servers
Getting Started
Documentation: https://getfacet.org/docs
GitHub: https://github.com/SoftInstigate/facet
Examples: Product Catalog Tutorial
RESTHeart Docs: https://restheart.org/docs
License
Facet is Apache 2.0 licensed—free for commercial use. Built on RESTHeart (AGPL v3 core, Apache 2.0 plugin interfaces).
Conclusion
Facet brings together the best of two worlds: Java's production-grade reliability and performance with the rapid development experience of PHP or Python frameworks. Convention over configuration, hot reload during development, deploy as a single JAR or native binary.
If you're building data-driven applications and want to skip the backend boilerplate while maintaining production-grade performance, give Facet a try.
Quick start:
curl -O https://getfacet.org/docker-compose.yml
docker-compose up -d
Or explore the product catalog example:
git clone https://github.com/SoftInstigate/facet.git
cd facet/examples/product-catalog
docker-compose up
Top comments (0)