primate
polymorphic development platform
Mix and match the best web tech, in one stack
backend
Write backend code in your language of choice, leveraging the power of Wasm. Mix routes of different backend languages, allowing your application to be written by different teams.
import { view } from "primate";
const posts = [{
id: 1,
title: "First post",
}];
export default {
get() {
return view("PostIndex.jsx", { posts });
},
};
import { view, Route } from "primate";
const posts = [{
id: 1,
title: "First post",
}];
export default {
get() {
return view("PostIndex.jsx", { posts });
},
} satisfies Route;
import "github.com/primatejs/go/primate"
func Get(request Request) any {
posts := Array{Object{
"id": 1,
"title": "First post",
}};
return primate.View("PostIndex.jsx", Object{ "posts": posts });
}
def get(request):
posts = [{
"id": 1,
"title": "First post",
}]
return Primate.view("PostIndex.jsx", { "posts": posts })
def get(request)
posts = [{
id: 1,
title: "First post",
}]
Primate.view("PostIndex.jsx", { posts: posts })
end
frontend
Seamlessly switch between frontend frameworks, with support for SSR, hydration and layouts across the board. You can even combine more than one framework in your application.
export default ({ posts }) => {
return (<>
<h1>All posts</h1>
{posts.map(post => (
<h2 key={post.id}>
<a href={`/post/${post.id}`}>
{post.title}
</a>
</h2>
))}
</>);
};
<script>
export let posts;
</script>
<h1>All posts</h1>
{#each posts as post}
<h2>
<a href="/post/{post.id}">
{post.title}
</a>
</h2>
{/each}
<template>
<h1>All posts</h1>
<div v-for="post in posts">
<h2>
<a :href="`/post/${post.id}`">
{{post.title}}
</a>
</h2>
</div>
</template>
import { For } from "solid-js/web";
export default ({ posts }) => {
return <>
<h1>All posts</h1>
<For each={posts}>{post =>
<h2>
<a href={`/post/${post.id}`}>
{post.title}
</a>
</h2>
}</For>
</>;
};
import { Component, Input } from "@angular/core";
import { CommonModule } from "@angular/common";
@Component({
selector: "post-index",
imports: [CommonModule],
template: `
<h1>All posts</h1>
<div *ngFor="let post of posts">
<h2>
<a href="/post/view/{{post.id}}">
{{post.title}}
</a>
</h2>
</div>
`,
standalone: true,
})
export default class PostIndex {
@Input() posts = [];
}
<script>
import { Component } from "@primate/frontend/webc";
export default class extends Component {
render() {
const { posts } = this.props;
return `<h1>All posts</h1>
${posts.map(post => `
<h2>
<a href="/post/view/${post.id}">
${post.title}
</a>
</h2>
`).join("")}
`;
},
};
</script>
runtime
Compare the performance of your application across different JavaScript runtimes. Use the comfort of one runtime during development and the speed gains of another in production.
npx -y primate@latest
deno run --allow-all npm:primate
bun --bun x primate
extensive, officially supported ecosystem
data handling
Validate input using Primate's runtime types. Persist information with stores, using any of the supported database drivers with a unified ORM interface, or write your own optimized, low-level store actions. Primate's ORM comes with automated transaction management and rollback on error, saving you writing boilerplate code in your application routes.
internationalization
Easily make your application international, using a unified API across different frontends with placeholder support and a built-in language switcher.
import t from "@primate/i18n/react";
import { locale } from "@primate/i18n/react";
export default function ({ username }) {
return <>
<h1>{t("welcome", { username })}</h1>
<p>{t("message")}</p>
{t("bye")}~
<h3>{t("switch-language")}</h3>
<div>
<a onClick={() => locale.set("en-US")}>
{t("English")}
</a>
</div>
<div>
<a onClick={() => locale.set("de-DE")}>
{t("German")}
</a>
</div>
</>;
}
<script>
import t from "@primate/i18n/svelte";
import { locale } from "@primate/i18n/svelte";
export let username;
</script>
<h1>{$t("welcome", { username })}</h1>
<p>{$t("message")}</p>
{$t("bye")}~
<h3>{$t("switch-language")}</h3>
<div>
<a on:click={() => locale.set("en-US")}>
{$t("English")}
</a>
</div>
<div>
<a on:click={() => locale.set("de-DE")}>
{$t("German")}
</a>
</div>
import t from "@primate/i18n/solid";
import { locale } from "@primate/i18n/solid";
export default function ({ username }) {
return <>
<h1>{t("welcome", { username })}</h1>
<p>{t("message")}</p>
{t("bye")}~
<h3>{t("switch-language")}</h3>
<div>
<a onClick={() => locale.set("en-US")}>
{t("English")}
</a>
</div>
<div>
<a onClick={() => locale.set("de-DE")}>
{t("German")}
</a>
</div>
</>;
}
all around
Use esbuild for hot reload during development and bundling in production, add user sessions or write your own modules using the available hooks.
more than all the rest, combined
Feature | Next | Nuxt | SvelteKit | Analog | Primate |
---|---|---|---|---|---|
Backend | |||||
JavaScript | ✓ | ✓ | ✓ | ✗ | ✓ |
TypeScript | ✓ | ✓ | ✓ | ✓ | ✓ |
Go | ✗ | ✗ | ✗ | ✗ | ✓ |
Python | ✗ | ✗ | ✗ | ✗ | ✓ |
Ruby | ✗ | ✗ | ✗ | ✗ | ✓ |
Frontend | |||||
React | ✓ | ✗ | ✗ | ✗ | ✓ |
Vue | ✗ | ✓ | ✗ | ✗ | ✓ |
Svelte | ✗ | ✗ | ✓ | ✗ | ✓ |
Angular | ✗ | ✗ | ✗ | ✓ | ✓ |
Solid | ✗ | ✗ | ✗ | ✗ | ✓ |
Web Components | ✗ | ✗ | ✗ | ✗ | ✓ |
HTMX | ✗ | ✗ | ✗ | ✗ | ✓ |
Handlebars | ✗ | ✗ | ✗ | ✗ | ✓ |
Markdown | ✗ | ✗ | ✗ | ✗ | ✓ |
Marko | ✗ | ✗ | ✗ | ✗ | ✓ |
Native runtime | |||||
Node | ✓ | ✓ | ✓ | ✓ | ✓ |
Deno | ✗ | ✗ | ✗ | ✗ | ✓ |
Bun | ✗ | ✗ | ✗ | ✗ | ✓ |
Data stores / ORM | |||||
SQLite | ✗ | ✗ | ✗ | ✗ | ✓ |
MongoDB | ✗ | ✗ | ✗ | ✗ | ✓ |
PostgreSQL | ✗ | ✗ | ✗ | ✗ | ✓ |
MySQL | ✗ | ✗ | ✗ | ✗ | ✓ |
SurrealDB | ✗ | ✗ | ✗ | ✗ | ✓ |
Ecosystem | |||||
I18N | ✓ | ✓ | ✗ | ✗ | ✓ |
Head Component | ✓ | ✓ | ✗ | ✗ | ✓ |
Route guards | ✗ | ✗ | ✗ | ✗ | ✓ |
Recursive layouts | ✓ | ✓ | ✓ | ✗ | ✓ |
WebSockets | ✗ | ✗ | ✗ | ✗ | ✓ |
Server-sent events | ✗ | ✗ | ✗ | ✗ | ✓ |
User sessions | ✗ | ✓ | ✗ | ✗ | ✓ |