The new datasette-apps plugin, launched today, allows developers to host custom HTML and JavaScript applications directly inside a Datasette instance. While the official announcement covers the mechanics, this piece explains the philosophy behind building a secure sandbox for user-generated code.
What this means for makers and artists
For creators building tools on top of data, this feature transforms Datasette from a static backend into a dynamic platform for rich interfaces. These apps are self-contained environments running in a strictly constrained <iframe> sandbox. They can execute read-only SQL queries against the host database and, with specific configuration, perform write operations as well.
Consider a custom timeline interface that aggregates news, blog posts, and releases into a single view. The application renders its own HTML, CSS, and JavaScript, yet it remains tethered to the underlying data via safe, controlled queries. This approach empowers makers to craft bespoke dashboards without needing to deploy separate servers or manage complex authentication flows.
To experience this capability, try the agent.datasette.io demo instance by signing in with GitHub.
Why build this?
Datasette has long served as a flexible backend for custom interfaces via its JSON API. This new plugin is the culmination of years of experimenting with client-side JavaScript to construct SQL queries directly within the browser-a technique originally conceived as an engineering joke at Eventbrite but proven to be highly productive.
The concept also draws inspiration from experiments with AI-generated code artifacts. The core insight is that pairing a self-contained HTML frontend with a persistent relational database backend creates an astonishingly powerful combination. It effectively brings the utility of generative AI tools into a production environment with access to real, structured data.
Security architecture
Allowing untrusted code to run on a sensitive domain requires rigorous isolation. The implementation relies on a specific combination of technologies:
- Sandboxed Iframes: The
<iframe sandbox="allow-scripts allow-forms">attribute prevents apps from accessing cookies,localStorage, or interacting with the parent application’s DOM. - Immutable Content Security Policy: An injected CSP header locks down access to external domains. Crucially, once set, this policy cannot be modified or removed by malicious JavaScript within the frame.
- Defence in Depth: While the CSP prevents requests to outside hosts, the system uses
MessageChannel()instead ofpostMessage()for internal communication. This ensures that if an iframe navigates away, the communication channel closes automatically, preventing command injection from external sources.
Safe write operations
While read-only queries are straightforward, enabling apps to modify data introduces significant risk. The solution leverages Datasette’s stored queries feature, recently upgraded in version 1.0a31.
Administrators can define specific “canned” queries that perform inserts or updates and then allow-list them for use by apps. This ensures that an application can only execute pre-approved mutations. For example, adding a task to a to-do list might look like this in the app’s code:
const result = await datasette.storedQuery**("todos"**("add_todo"**(**(
title**("Buy milk"**(**(**(
due_date**("2026-06-20"**(**(**(
priority**("high"**(**(**(**(
completed**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(**(<Source Read original →


