ANGULAR SERVER ARCHITECTURE
The server layer Angular was missing.
Strata brings Server Components to Angular and Analog: render components on the server, keep their code and dependencies out of the browser, and hydrate only the pieces that need interaction. When you need HTTP endpoints, structure them with Angular-native controllers.
Two capabilities, one server model.
What Strata adds
Built on the stack you use
ExperimentalPreview
STRATA SERVER COMPONENTS
Angular components that stay on the server.
Server Components run Angular components on the server without shipping their implementation or server dependencies to the browser. Interactive children stay interactive: only explicit client boundaries hydrate.
ServerComponentsShowcaseServer Component server ServerComponentFactsRepositoryInjected service server server-component-proofTransitive import server ServerComponentDemoClient island → browser | ServerComponentsShowcase | server only |
|---|---|
| ServerComponentFactsRepository | server only |
| server-component-proof | server only |
| ServerComponentDemo | browser |
Live · rendered on the server
This panel is the proof.
- Server Component
- ServerComponentsShowcase
- Implementation
- server only
- Data dependency
- server only
- Rendered by
- Angular + Analog
Client island · hydrated in the browser
Props from the server: ServerComponentsShowcase with 3 server-only modules left behind.
Preview status. Currently dogfooded in this site and qualified in the repository on Node/Nitro and Cloudflare workerd. The public package is not released yet.
Navigation. The preview supports initial and document navigation. Angular Router SPA navigation into a new Server Component subtree is not supported yet.
SERVER PARENT, CLIENT ISLAND
One decorator, one explicit boundary.
import { Component, inject } from "@angular/core";
import { ServerComponent, StrataClientBoundary } from "@strata-sc/server-components";
import { AddToCartComponent } from "./add-to-cart.component";
import { ProductRepository } from "./product.repository";
@ServerComponent()
@Component({
selector: "product-summary",
imports: [AddToCartComponent, StrataClientBoundary],
template: `
<h1>{{ product.name }}</h1>
<p>{{ product.description }}</p>
<add-to-cart
[productId]="product.id"
[strataClient]="{ productId: product.id }"
/>
`,
})
export class ProductSummary {
// Server-only: neither this class nor ProductRepository
// ever enters the browser bundle.
private readonly products = inject(ProductRepository);
protected readonly product = this.products.findById("42");
}@ServerComponent() sits on an ordinary @Component. It renders with inject() on the server; the browser receives an empty surrogate.
Name what hydrates.
[strataClient] marks the child that ships. Its props cross as plain data: strings, numbers, booleans and null in a flat object.
Preview, not a package yet.
@strata-sc/server-components is private and experimental. It powers this page, but it is not published for installation.
ONE SERVER MODEL
Server-first, by construction.
Strata makes server-side Angular a coherent application model: server-rendered UI, explicit client islands and structured HTTP APIs, built on Angular primitives and the Analog/Nitro runtime.
Component implementations, repositories and server dependencies never enter the browser graph. The build swaps each Server Component for an empty surrogate.
Mark explicit client boundaries with [strataClient]. Only those Angular components hydrate, from plain-data props the server serialized.
Use Angular-native controllers when you need HTTP endpoints, registered on the Nitro router you already own.
STRUCTURED APIs WHEN YOU NEED THEM
Controllers for the HTTP side.
import { Controller, Delete, Get, Patch, Post, Put } from "@strata-sc/core";
import type { StrataAnalogRequest } from "@strata-sc/analog";
@Controller("/api/users")
export class UsersController {
@Get()
list() {
return [{ id: "1", name: "Ada" }];
}
@Post()
async create(request: StrataAnalogRequest) {
return request.readJson<{ name: string }>();
}
@Put("/:id")
async replace(request: StrataAnalogRequest) {
return { id: request.params["id"], ...(await request.readJson<{ name: string }>()) };
}
@Patch("/:id")
async rename(request: StrataAnalogRequest) {
const { name } = await request.readJson<{ name: string }>();
return { id: request.params["id"], name };
}
@Delete("/:id")
remove(request: StrataAnalogRequest) {
return { deleted: request.params["id"] };
}
} Controllers are ordinary classes. @Get, @Post, @Put, @Patch and @Delete create portable metadata with standard decorators, not a second application model.
Attach to a runtime when ready.
Register the class on Nitro's router from a server plugin with @strata-sc/analog. Native routes keep working beside it.
ANALOG, WITHOUT A DETOUR
Native to the Nitro seam.
The Analog adapter registers controllers where Nitro expects them: in a server plugin, on the router it already owns.
import { registerControllers } from "@strata-sc/analog";
import { defineNitroPlugin } from "nitropack/runtime";
import { UsersController } from "../strata/users.controller";
export default defineNitroPlugin((nitroApp) => {
registerControllers(nitroApp.router, [UsersController]);
});TWO AXES, CLEAR OWNERSHIP
Strata never replaces your server.
It owns two precise seams: which parts of the UI graph stay on the server, and how controllers register on the router you already have. Angular, Analog and Nitro keep their lifecycles.
- UI graph: Server Components and their dependencies stay server-side
- Client boundaries are the only UI that hydrates
- Controllers register on Nitro/H3; native routes stay
EARLY, OPEN, AND DELIBERATE
Build the next layer with us.
Strata is experimental today. Server Components are a private preview dogfooded on this site; controllers ship as 0.x releases. The design work is public and contributions are welcome.